This is probably the most comprehensive Java interview stereotype

Features of Java

Java is an object-oriented programming language . The difference between object-oriented and process-oriented refers to the next question.

Java is platform independent and portable .

  • Java has a slogan: Write once, run anywhere, write once, run anywhere. This is also the charm of Java. And it is the Java virtual machine JVM that realizes this feature. Compiled Java programs can run on any platform with a JVM. You can write code on the windows platform, and then get it to run on linux. As long as you compile the code into a .class file after writing the code, and then package the class file into a Java package, the jar package can run on different platforms.

Java is robust .

  • Java is a strongly typed language, which allows for extended compile-time checking of potential type mismatches. Java requires explicit method declarations, it does not support C-style implicit declarations. These strict requirements ensure that the compiler catches calling errors, which leads to more reliable programs. The most comprehensive Java interview site
  • Exception handling is another feature in Java that makes programs more robust. An exception is a signal of some kind of abnormal condition similar to an error. Using try/catch/finallystatements, the programmer can find the error handling code, which simplifies the task of error handling and recovery.

How does Java achieve cross-platform?

Java is cross-platform through JVM (Java Virtual Machine).

JVM can be understood as a piece of software, and different platforms have different versions. The Java code we write will generate a .class file (bytecode file) after compilation. The Java virtual machine is responsible for translating the bytecode file into machine code under a specific platform, which can only be run after being translated into machine code by the JVM. The bytecode compiled and generated under different platforms is the same, but the machine code translated by the JVM is different.

As long as the corresponding JVM is installed on different platforms, you can run the bytecode file and run the Java program we wrote.

Therefore, running a Java program must have the support of the JVM, because the compiled result is not machine code, and must be translated by the JVM before it can be executed.

This article has been included in the Github warehouse, which includes computer foundation, Java foundation, multithreading, JVM, database, Redis, Spring, Mybatis, SpringMVC, SpringBoot, distributed, microservices, design patterns, architecture, school recruitment and social recruitment sharing, etc. Core knowledge points, welcome to star~

Github address

If you can't access Github, you can access the code cloud address.

Code cloud address

Difference between Java and C++

  • Java is a pure object-oriented language, all objects inherit from java.lang.Object, C++ is compatible with C, and supports not only object-oriented but also process-oriented.
  • Java achieves cross-platform features through virtual machines, and C++ depends on specific platforms.
  • Java has no pointers, and its references can be understood as safe pointers, while C++ has the same pointers as C.
  • Java supports automatic garbage collection, while C++ requires manual collection.
  • Java does not support multiple inheritance and can only achieve the same purpose by implementing multiple interfaces, while C++ supports multiple inheritance.

The relationship between JDK/JRE/JVM

JVM

The English name (Java Virtual Machine) is the familiar Java virtual machine. The core of Java's ability to run across platforms lies in the JVM.

All java programs will first be compiled into .class class files, which can be executed on a virtual machine. That is to say, the class file does not directly interact with the operating system of the machine, but indirectly interacts with the operating system through the virtual machine, and the virtual machine interprets the program to the local system for execution.

There are different jvm implementations for different systems, including Linux version and Windows version, but the compiled bytecode of the same piece of code is the same. This is why Java can be cross-platform, write once and run in multiple places.

JRE

The English name (Java Runtime Environment) is the Java runtime environment. The Java programs we write must run on the JRE. It mainly consists of two parts, JVM and Java core class library.

JRE is a Java runtime environment, not a development environment, so it does not include any development tools, such as compilers and debuggers.

If you just want to run Java programs instead of developing Java programs, then you only need to install JRE.

Finally, I would like to share with you a Github repository, which has more than 300 classic computer book PDFs compiled by Dabin, including C language, C++, Java, Python, front-end, database, operating system, computer network, data structure and algorithm, machine learning , programming life , etc., you can star it, next time you look for a book directly search on it, the warehouse is continuously updated~

Github address

JDK

The English name (Java Development Kit) is the Java Development Kit

Students who have studied Java should have installed JDK. After we installed the JDK, the directory structure is like this

It can be seen that there is a JRE in the JDK directory, that is, the JRE has been integrated in the JDK, and there is no need to install the JRE separately.

In addition, there are some useful tools in JDK, such as jinfo, jps, jstack, etc.

Finally, summarize the relationship between JDK/JRE/JVM and the three of them

JRE = JVM + Java core class library

JDK = JRE + Java Tools + Compiler + Debugger

Is the Java program compiled and executed or interpreted?

First look at what is a compiled language and an interpreted language.

compiled language

Before the program is run, the source program is compiled into a executable binary of the machine code by the compiler. When the program is executed later, there is no need to compile it again.

Advantages: Compilers generally have a pre-compilation process to optimize the code. Because the compilation is done only once, no compilation is required at runtime, so the program execution efficiency of the compiled language is high, and it can run independently from the language environment.

Disadvantage: If you need to modify after compilation, you need to recompile the entire module. When compiling, the machine code is generated according to the corresponding operating environment. There will be problems in porting between different operating systems. Different executable files need to be compiled according to the running operating system environment.

Summary : fast execution speed and high efficiency; relying on compilers and poor cross-platform performance.

Representative languages : C, C++, Pascal, Object-C, and Swift.

interpreted language

Definition: The source code of an interpreted language is not directly translated into machine code, but translated into intermediate code first, and then the interpreter interprets and runs the intermediate code. The source program is translated into machine code when it is running, one sentence is translated, and then one sentence is executed until the end.

advantage:

  1. It has good platform compatibility and can run in any environment, provided that an interpreter (such as a virtual machine) is installed.
  2. Flexible, you can directly modify the code when you modify it, and you can deploy it quickly without downtime for maintenance.

Disadvantages: It needs to be explained every time it runs, and its performance is not as good as that of compiled languages.

Summary: Interpreted languages ​​have slow execution speed and low efficiency; rely on interpreters and have good cross-platform performance.

Representative languages: JavaScript, Python, Erlang, PHP, Perl, Ruby.

For a language like Java, its source code will first be compiled into bytecode by javac , and then converted into machine code by jvm for execution, that is, interpreting and compiling are used together, so it can be called a hybrid or semi compiled type.

What is the difference between object-oriented and process-oriented?

Object-oriented and process-oriented are a kind of software development thought.

  • Process-oriented is to analyze the steps needed to solve the problem, and then use functions to implement these steps, and call them sequentially when using them.

  • Object-oriented is to decompose the constituent problem affairs into individual objects, design these objects separately, and then assemble them into a system with complete functions. Process-oriented is only implemented with functions, and object-oriented is implemented with classes to implement each functional module.

Taking backgammon as an example, the process-oriented design idea is the first step to analyze the problem:

1. Start the game, 2. The sunspots go first, 3. Draw the picture, 4. Determine whether to win or lose, 5. It is Bai's turn, 6. Draw the picture, 7. Determine whether to win or lose, 8. Return to step 2, 9. Output the final result.
Implement each of the above steps with separate functions, and the problem is solved.

The object-oriented design is to solve the problem from another way of thinking. The whole backgammon can be divided into:

  1. black and white
  2. Chessboard system, responsible for drawing the picture
  3. The rule system is responsible for determining things such as fouls, wins and losses, etc.

The black and white sides are responsible for accepting the user's input and notifying the chessboard system that the layout of the chess pieces has changed. The chessboard system is responsible for displaying the change on the screen after receiving the information about the change of the chess pieces. At the same time, it uses the rule system to judge the chess game.

What are the characteristics of object-oriented?

Object-oriented four characteristics: encapsulation, inheritance, polymorphism, abstraction

1. Encapsulation is to hide the information of the class inside the class, and does not allow direct access by external programs, but realizes the operation and access to the hidden information through the methods of this class. Good packaging reduces coupling.

2. Inheritance is to derive a new class from an existing class. The new class inherits the attributes and behaviors of the parent class, and can expand new capabilities, greatly increasing the reusability and ease of maintenance of the program. In Java, it is single inheritance, which means that a subclass has only one parent class.

3. Polymorphism is the ability to have multiple different manifestations of the same behavior. Change the code bound at runtime of the program without modifying the program code. The three elements of polymorphism: inheritance, rewriting, and parent class references pointing to subclass objects.

  • Static polymorphism: Implemented through overloading, the same method has different parameter lists, and different processing can be done according to different parameters.
  • Dynamic polymorphism: overriding methods of the parent class in the child class. During operation, the actual type of the referenced object is judged, and the corresponding method is called according to its actual type.

4. Abstraction. Abstract objective things with code.

Six principles of object-oriented programming

  • Object single responsibility : The objects we design and create must have clear responsibilities, such as commodity classes, and the relevant attributes and methods in them must be related to commodities, and irrelevant content such as orders cannot appear. The class here can be a module, class library, assembly, not just a class.
  • Li-style substitution principle : Subclasses can completely replace parent classes, but not vice versa. Usually used when implementing an interface. Because the subclass can completely replace the base (parent) class, then the parent class has many subclasses, which is easy to expand in subsequent program extensions, and the program can be extended without modification at all. For example, the implementation of IA is A, because the project requirements have changed, and now a new implementation is needed, just replace the interface directly at the container injection point.
  • Dimit's law , also known as the minimum principle, or minimum coupling. Usually when designing or developing a program, try to have high cohesion and low coupling. Dependencies arise when two classes interact. And Dimit's law suggests that the less this dependence, the better. Just like when a constructor injects a parent class object, when you need to rely on an object, you don’t care how it is implemented internally, but inject the corresponding implementation into the container, which not only conforms to the principle of Li-style replacement, but also helps to understand The role of coupling.
  • The principle of opening and closing: open for expansion and closed for modification. When the project requirements change, it is necessary not to modify the original code as much as possible, but to expand on the original basis.
  • Dependency inversion principle : high-level modules should not directly depend on the concrete implementation of low-level modules, but should depend on the low-level abstractions. Interfaces and abstract classes should not depend on implementing classes, and implementing classes depend on interfaces or abstract classes.
  • Interface Segregation Principle : In the process of an object interacting with another object, the dependent content is the least. That is to say, when the interface is designed, the content of the interface should be reduced as much as possible while following the single responsibility of the object.

Short version :

  • Single Responsibility: Object design requires independence, and universal objects cannot be designed.
  • Open-Closed Principle: Object modifications are minimized.
  • Li-style replacement: abstraction can be replaced by concrete in program extension (interface, parent class, class object that can be implemented, subclass replacement object)
  • Dimit: High cohesion, low coupling. Try not to rely on details.
  • Dependency Inversion: Programming to the Abstraction. That is, parameter passing, or return value, can use parent class type or interface type. In a broad sense: based on interface programming, the interface framework is designed in advance.
  • Interface isolation: The size of the interface design should be moderate. If it is too large, it will cause pollution, if it is too small, it will cause trouble in calling.

Are arrays objects?

Let me talk about the concept of objects first. An object is an instance created according to a certain class, representing a specific individual in a certain type of thing.

Objects have various properties and have some specific behaviors. From the computer's point of view, an object is a memory block in memory, which encapsulates some data, that is, various attributes defined in the class.

Therefore, objects are used to encapsulate data.

Arrays in java have some basic characteristics of other objects in java. For example, some data is encapsulated, attributes can be accessed, and methods can also be called.

Therefore, it can be said that arrays are objects.

The fact that arrays are objects can also be verified through code. For example, the following code, the output result is java.lang.Object.

Class clz = int[].class;
System.out.println(clz.getSuperclass().getName());

From this, it can be seen that the parent class of the array class is the Object class, so it can be inferred that the array is an object.

What are the basic data types of Java?

  • byte,8bit
  • char,16bit
  • short,16bit
  • int,32bit
  • float,32bit
  • long,64bit
  • double,64bit
  • boolean, only two values: true, false, can use 1 bit to store
simple type boolean byte char short Int long float double
binary digits 1 8 16 16 32 64 32 64
Packaging Boolean Byte Character Short Integer Long Float Double

In the Java specification, there is no clear indication of the size of boolean. In the "Java Virtual Machine Specification", a single boolean occupies 4 bytes, and a boolean array defines 1 byte. It depends on virtual machine implementation is in accordance with the specification , so boolean occupies 1 byte or 4 bytes. Bytes are all possible.

Why can't the amount be expressed in floating point?

Since the decimals stored in the computer are actually approximate values ​​of decimals, not exact values, therefore, do not use floating-point numbers in the code to represent important indicators such as money.

It is recommended to use BigDecimal or Long to represent the amount.

What are pass by value and pass by reference?

  • Value transfer is for basic variables, and what is transferred is a copy of the variable, and changing the copy does not affect the original variable.
  • Passing by reference is generally for object variables. What is passed is a copy of the address of the object, not the original object itself. The two point to the same memory space. So operations on the referenced object will also change the original object.

There is no pass by reference in java, only pass by value . That is, there is no such situation that variable a points to variable b, and variable b points to an object.

Know Java's wrapper types? Why do you need a wrapper class?

Java is an object-oriented language, and there are many places where you need to use objects instead of primitive data types. For example, in the collection class, we cannot put int, double and other types into it. Because the container of the collection requires the elements to be of type Object.

In order to make the basic type also have the characteristics of the object, the packaging type appears. It is equivalent to wrapping the basic type, making it have the nature of an object, and adding properties and methods to it, enriching the operations of the basic type.

Automatic boxing and unboxing

The basic data types in Java and their corresponding wrapper classes are shown in the following table:

primitive type type of packaging
boolean Boolean
byte Byte
char Character
float Float
int Integer
long Long
short Short
double Double

Boxing: Converts an underlying type into a wrapped type.

Unboxing: converts the wrapped type to the underlying type.

When the basic types and their packaging classes have the following situations, the compiler will automatically box or unbox for us:

  • Assignment operations (boxing or unboxing)
  • Perform mixed operations of addition, subtraction, multiplication, and division (unboxing)
  • Perform >,<,== comparison operations (unboxing)
  • Call equals for comparison (boxing)
  • When adding basic type data to collection classes such as ArrayList and HashMap (boxing)

Sample code:

Integer x = 1; // 装箱 调⽤ Integer.valueOf(1)
int y = x; // 拆箱 调⽤了 X.intValue()

Here is a common interview question:

Integer a = 100;
Integer b = 100;
System.out.println(a == b);

Integer c = 200;
Integer d = 200;
System.out.println(c == d);

output:

true
false

Why is the third output false? Just look at the source code of the Integer class.

public static Integer valueOf(int i) {
    
    
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

Integer c = 200;will call call Integer.valueOf(200). As can be seen from the source code of Integer's valueOf(), the implementation here is not a simple new Integer, but uses IntegerCache as a cache.

private static class IntegerCache {
    
    
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
    
    
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
    
    
            try {
    
    
                int i = parseInt(integerCacheHighPropValue);
                i = Math.max(i, 127);
                // Maximum array size is Integer.MAX_VALUE
                h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
            } catch( NumberFormatException nfe) {
    
    
                // If the property cannot be parsed into an int, ignore it.
            }
        }
        high = h;
    }
    ...
}

This is a section of the IntegerCache static code block. The default lower limit of the Integer cache is -128, and the upper limit is 127 by default. When assigning 100 to Integer, it happens to be within this range, so the corresponding Integer is fetched from the cache and returned, so a and b return the same object, so the comparison is equal. When assigning 200 ==to Integer, it is not in the cache In the range, so it will be new Integer and return, of course, ==the result of the comparison is not equal.

Why is String immutable?

Let's first look at what an immutable object is.

An object is immutable if its state cannot be changed after it has been created. Cannot change the state means that the member variables in the object cannot be changed, including the value of the basic data type cannot be changed, the variable of the reference type cannot point to other objects, and the state of the object pointed to by the reference type cannot be changed.

Next, look at the source code of the Java8 String class:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
    
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
}

It can be seen from the source code that the String object is actually a character internally, which is stored in the value array.

The value array is modified with final, and the value of the final modified variable cannot be modified. Therefore, value cannot point to other objects.

All fields inside the String class are private, that is, they are modified by private. And String does not provide external methods to modify the internal state, so the value array cannot be changed.

Therefore, String is immutable.

So why is String designed to be immutable?

There are mainly the following reasons:

  1. thread safe . The same string instance can be shared by multiple threads, because strings are immutable and thread-safe.
  2. Support hash mapping and caching . Because the hash value of String is often used, such as as the key of Map, the immutable feature makes the hash value unchanged and does not need to be recalculated.
  3. For security reasons . The network address URL, file path path, and password are usually stored in the String type. If the String is not fixed, it will cause various security risks. For example, if the password is saved with the String type, it will remain in memory until the garbage collector clears it. If the String class is not fixed, then this password may be changed, resulting in security risks.
  4. String constant pool optimization . After the String object is created, it will be cached in the string constant pool. The next time you need to create the same object, you can directly return the cached reference.

Since our String is immutable, there are many substring, replace, replaceAll methods inside it. These methods seem to change the String object? How to explain it?

Actually not, every time we call replace and other methods, we will actually create a new object in the heap memory. Then its value array reference points to a different object.

Why does JDK9 change the underlying implementation of String from char[] to byte[]?

Mainly to save the memory occupied by String .

In the heap memory of most Java programs, String occupies the largest space, and most Strings only have Latin-1 characters, and these Latin-1 characters only need 1 byte.

Before JDK9, JVM uses char array storage for String, and each char occupies 2 bytes, so even if the string only needs 1 byte, it must be allocated according to 2 bytes, wasting half of the memory space.

After JDK9, for each string, it will be judged whether it has only Latin-1 characters. If it is, the memory will be allocated according to the specification of 1 byte. If not, the memory will be allocated according to the specification of 2 bytes. In this way This will increase the memory usage, and at the same time, the number of GC will be reduced to improve efficiency.

However, the characters supported by the Latin-1 code set are limited. For example, Chinese characters are not supported. Therefore, for Chinese strings, UTF16 encoding (two bytes) is used, so there is no difference between byte[] and char[].

Difference between String, StringBuffer and StringBuilder

1. Variability

  • String is immutable
  • StringBuffer and StringBuilder mutable

2. Thread safety

  • String is immutable and thus thread-safe
  • StringBuilder is not thread safe
  • StringBuffer is thread-safe and uses synchronized internally for synchronization

What is StringJoiner?

StringJoiner is a new API added in Java 8. It is implemented based on StringBuilder and is used to realize the scenario of splicing strings through separators.

StringJoiner has two construction methods, the first construction requires delimiter, prefix and suffix to be passed in order. The second construct requires only the delimiter to be passed in (prefix and suffix default to empty strings).

StringJoiner(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
StringJoiner(CharSequence delimiter)

In some string splicing scenarios, it is cumbersome to use StringBuffer or StringBuilder.

Like the following example:

List<Integer> values = Arrays.asList(1, 3, 5);
StringBuilder sb = new StringBuilder("(");

for (int i = 0; i < values.size(); i++) {
    
    
	sb.append(values.get(i));
	if (i != values.size() -1) {
    
    
		sb.append(",");
	}
}

sb.append(")");

However, the StringJoiner is used to join the elements of the List, and the code looks more concise.

List<Integer> values = Arrays.asList(1, 3, 5);
StringJoiner sj = new StringJoiner(",", "(", ")");

for (Integer value : values) {
    
    
	sj.add(value.toString());
}

In addition, like the Collectors.joining(“,”) that is often used in normal times, the underlying layer is implemented through StringJoiner.

The source code is as follows:

public static Collector<CharSequence, ?, String> joining(
    CharSequence delimiter,CharSequence prefix,CharSequence suffix) {
    
    
    return new CollectorImpl<>(
            () -> new StringJoiner(delimiter, prefix, suffix),
            StringJoiner::add, StringJoiner::merge,
            StringJoiner::toString, CH_NOID);
}

What are the commonly used methods of the String class?

  • indexOf(): Returns the index of the specified character.
  • charAt(): Returns the character at the specified index.
  • replace(): String replacement.
  • trim(): Removes blanks at both ends of the string.
  • split(): splits the string and returns a split string array.
  • getBytes(): returns the byte type array of the string.
  • length(): Returns the length of the string.
  • toLowerCase(): Convert the string to lowercase letters.
  • toUpperCase(): Convert the string to uppercase characters.
  • substring(): Intercepts a string.
  • equals(): String comparison.

How many objects will new String("dabin") create?

Using this method will create two string objects (provided that there is no "dabin" string object in the string constant pool).

  • "dabin" is a string literal, so a string object will be created in the string constant pool during compilation, pointing to this "dabin" string literal;
  • Using new will create a string object in the heap.

What is a string constant pool?

String constant pool (String Pool) saves all string literals, which are determined at compile time. The string constant pool is located in the heap memory and is specially used to store string constants. When creating a string, the JVM first checks the string constant pool. If the string already exists in the pool, its reference is returned. If it does not exist, the string is created and placed in the pool, and its reference is returned.

What is the maximum length of String?

The String class provides a length method, the return value is int type, and the upper limit of the value of int is 2^31 -1.

So in theory the maximum length of String is 2^31 -1.

How much memory is needed to achieve this length ?

String internally uses a char array to maintain the character sequence, and a char occupies two bytes. If the maximum length of String is 2^31 -1, then the memory space occupied by the largest string is approximately equal to 4GB.

In other words, we need to have a JVM running memory greater than 4GB.

Where is String generally stored in the JVM ?

The storage of strings in the JVM is divided into two cases, one is the String object, which is stored in the JVM stack. One is a string constant, which is stored in the constant pool.

Under what circumstances will strings be stored in the constant pool ?

When a string is declared through a literal value, such as String s = "program new Dabin";, this string will enter the constant pool in the form of a constant after compilation.

Is the maximum length of the string in the constant pool 2^31-1 ?

No, the constant pool has additional restrictions on the length of String. . UTF-8 encoded Unicode strings in Java are represented as CONSTANT_Utf8 types in the constant pool.

CONSTANT_Utf8_info {
    
    
    u1 tag;
    u2 length;
    u1 bytes[length];
}

length here represents the length of the string, the type of length is u2, and u2 is an unsigned 16-bit integer, that is to say, the maximum length can be 2^16-1 or 65535.

However, the javac compiler has made restrictions and requires length < 65535. So the maximum length of a string constant in the constant pool is 65535 - 1 = 65534.

Finally, to summarize:

String has different length limits in different states.

  • String constant length cannot exceed 65534
  • The length of the string in the heap does not exceed 2^31-1

What are the common methods of Object?

A question that often appears in Java interviews, the common method of Object. Let me sort it out for you.

Object common methods are: toString(), equals(), hashCode(), clone()etc.

Outputs the object address by default.

public class Person {
    
    
    private int age;
    private String name;

    public Person(int age, String name) {
    
    
        this.age = age;
        this.name = name;
    }

    public static void main(String[] args) {
    
    
        System.out.println(new Person(18, "程序员大彬").toString());
    }
    //output
    //me.tyson.java.core.Person@4554617c
}

The toString method can be rewritten to output the object value according to the rewriting logic.

public class Person {
    
    
    private int age;
    private String name;

    public Person(int age, String name) {
    
    
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return name + ":" + age;
    }

    public static void main(String[] args) {
    
    
        System.out.println(new Person(18, "程序员大彬").toString());
    }
    //output
    //程序员大彬:18
}

equals

By default, compare whether two reference variables point to the same object (memory address).

public class Person {
    
    
    private int age;
    private String name;

    public Person(int age, String name) {
    
    
       this.age = age;
       this.name = name;
    }

    public static void main(String[] args) {
    
    
        String name = "程序员大彬";
        Person p1 = new Person(18, name);
        Person p2 = new Person(18, name);

        System.out.println(p1.equals(p2));
    }
    //output
    //false
}

The equals method can be rewritten to judge whether age and name are equal:

public class Person {
    
    
    private int age;
    private String name;

    public Person(int age, String name) {
    
    
        this.age = age;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (o instanceof Person) {
    
    
            Person p = (Person) o;
            return age == p.age && name.equals(p.name);
        }
        return false;
    }

    public static void main(String[] args) {
    
    
        String name = "程序员大彬";
        Person p1 = new Person(18, name);
        Person p2 = new Person(18, name);

        System.out.println(p1.equals(p2));
    }
    //output
    //true
}

hashCode

Map the information related to the object into a hash value. The default implementation hashCode value is converted based on the memory address.

public class Cat {
    
    
    public static void main(String[] args) {
    
    
        System.out.println(new Cat().hashCode());
    }
    //out
    //1349277854
}

clone

Java assignment is to copy an object reference. If we want to get a copy of an object, it is impossible to use the assignment operation. The Object object has a clone() method, which implements the

The copy of each attribute in the image, but its visible range is protected.

protected native Object clone() throws CloneNotSupportedException;

So the premise of using cloning for entity classes is:

  • Implement the Cloneable interface, which is a marker interface and has no methods of its own. This should be a convention. When calling the clone method, it will determine whether the Cloneable interface is implemented. If Cloneable is not implemented, an exception CloneNotSupportedException will be thrown.
  • Override the clone() method, and raise the visibility to public.
public class Cat implements Cloneable {
    
    
    private String name;

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Cat c = new Cat();
        c.name = "程序员大彬";
        Cat cloneCat = (Cat) c.clone();
        c.name = "大彬";
        System.out.println(cloneCat.name);
    }
    //output
    //程序员大彬
}

getClass

Returns the runtime class of this Object, often used in java reflection mechanism.

public class Person {
    
    
    private String name;

    public Person(String name) {
    
    
        this.name = name;
    }

    public static void main(String[] args) {
    
    
        Person p = new Person("程序员大彬");
        Class clz = p.getClass();
        System.out.println(clz);
        //获取类名
        System.out.println(clz.getName());
    }
    /**
     * class com.tyson.basic.Person
     * com.tyson.basic.Person
     */
}

wait

After the current thread calls the wait() method of the object, the current thread will release the object lock and enter the waiting state. Wait for other threads to call notify()/notifyAll() of this object to wake up or wait for the timeout wait(long timeout) to wake up automatically. The thread needs to acquire the obj object lock before calling obj.wait().

notify

obj.notify() wakes up a single thread waiting on this object, the choice is arbitrary. notifyAll() wakes up all threads waiting on this object.

Talk about deep copy and shallow copy?

Shallow copy : The copy object and the reference type of the original object refer to the same object.

In the following example, there is a Person object in the Cat object. After calling clone, the cloned object and the Person of the original object refer to the same object, which is a shallow copy.

public class Cat implements Cloneable {
    
    
    private String name;
    private Person owner;

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Cat c = new Cat();
        Person p = new Person(18, "程序员大彬");
        c.owner = p;

        Cat cloneCat = (Cat) c.clone();
        p.setName("大彬");
        System.out.println(cloneCat.owner.getName());
    }
    //output
    //大彬
}

Deep copy : The copy object and the reference type of the original object refer to different objects.

In the following example, not only super.clone is called in the clone function, but also the clone method of the Person object is called (Person also implements the Cloneable interface and overrides the clone method), thus realizing deep copy. As you can see, the value of the copied object will not be affected by the original object.

public class Cat implements Cloneable {
    
    
    private String name;
    private Person owner;

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        Cat c = null;
        c = (Cat) super.clone();
        c.owner = (Person) owner.clone();//拷贝Person对象
        return c;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Cat c = new Cat();
        Person p = new Person(18, "程序员大彬");
        c.owner = p;

        Cat cloneCat = (Cat) c.clone();
        p.setName("大彬");
        System.out.println(cloneCat.owner.getName());
    }
    //output
    //程序员大彬
}

If the hashCode() of two objects is the same, is equals() necessarily true?

The relationship between equals and hashcode:

  1. If two objects call equals to compare and return true, then their hashCode values ​​must be the same;
  2. If two objects have the same hashCode, they are not necessarily the same.

The hashcode method is mainly used to improve the efficiency of object comparison . First compare hashcode(). If they are not the same, then there is no need to compare equals, which greatly reduces the number of equals comparisons. When the number of comparison objects is large time can improve efficiency.

Why must rewrite hashCode when rewriting equals?

The reason why rewriting equals()is rewriting hashcode()is to ensure that equals()the hashcode value is also consistent when the method returns true. If rewriting is equals()not rewritten hashcode(), two objects will be equal but hashcode()not equal. In this way, when one of the objects is used as a key to save it in hashMap, hashTable or hashSet, and then another object is used as a key to find them, it will not be found.

How many ways does Java create objects?

There are several ways to create objects in Java:

  • Objects are created with the new statement.
  • Using reflection, objects are created using Class.newInstance().
  • Call the clone() method of the object.
  • Use the deserialization method to call the readObject() method of the java.io.ObjectInputStream object.

Talk about the order of class instantiation

The order of class instantiation in Java:

  1. Static attributes, static code blocks.
  2. Ordinary attributes, ordinary code blocks.
  3. Construction method.
public class LifeCycle {
    
    
    // 静态属性
    private static String staticField = getStaticField();

    // 静态代码块
    static {
    
    
        System.out.println(staticField);
        System.out.println("静态代码块初始化");
    }

    // 普通属性
    private String field = getField();

    // 普通代码块
    {
    
    
        System.out.println(field);
        System.out.println("普通代码块初始化");
    }

    // 构造方法
    public LifeCycle() {
    
    
        System.out.println("构造方法初始化");
    }

    // 静态方法
    public static String getStaticField() {
    
    
        String statiFiled = "静态属性初始化";
        return statiFiled;
    }

    // 普通方法
    public String getField() {
    
    
        String filed = "普通属性初始化";
        return filed;
    }

    public static void main(String[] argc) {
    
    
        new LifeCycle();
    }

    /**
     *      静态属性初始化
     *      静态代码块初始化
     *      普通属性初始化
     *      普通代码块初始化
     *      构造方法初始化
     */
}

What is the difference between equals and ==?

  • For primitive data types, == compares their values. Basic data types have no equal method;

  • For compound data types, == compares their storage addresses (whether they are the same object). equals()By default, the address value is compared. If it is rewritten, it will be compared according to the rewriting logic.

What are the common keywords?

static

static can be used to modify the member methods and member variables of the class.

Static variables are also called static variables . The difference between static variables and non-static variables is that static variables are shared by all objects and have only one copy in memory. They are initialized if and only when the class is first loaded. Non-static variables are owned by the object and are initialized when the object is created. There are multiple copies, and the copies owned by each object do not affect each other.

In the following example, if age is a non-static variable, the print result of p1 is: ; Name:zhangsan, Age:10if age is modified with static, the print result of p1 is: Name:zhangsan, Age:12, because there is only one copy of the static variable in memory.

public class Person {
    
    
    String name;
    int age;
    
    public String toString() {
    
    
        return "Name:" + name + ", Age:" + age;
    }
    
    public static void main(String[] args) {
    
    
        Person p1 = new Person();
        p1.name = "zhangsan";
        p1.age = 10;
        Person p2 = new Person();
        p2.name = "lisi";
        p2.age = 12;
        System.out.println(p1);
        System.out.println(p2);
    }
    /**Output
     * Name:zhangsan, Age:10
     * Name:lisi, Age:12
     *///~
}

A static method is generally called a static method . Static methods can be accessed without relying on any object, and static methods can be called through the class name.

public class Utils {
    
    
    public static void print(String s) {
    
    
        System.out.println("hello world: " + s);
    }

    public static void main(String[] args) {
    
    
        Utils.print("程序员大彬");
    }
}

Static code blocks are only executed once when the class is loaded. In the following example, startDate and endDate are assigned when the class is loaded.

class Person  {
    
    
    private Date birthDate;
    private static Date startDate, endDate;
    static{
    
    
        startDate = Date.valueOf("2008");
        endDate = Date.valueOf("2021");
    }

    public Person(Date birthDate) {
    
    
        this.birthDate = birthDate;
    }
}

static inner class

In a static method , the use of a non-static inner class depends on an instance of an outer class, which means that an instance of an outer class needs to be created before it can be used to create a non-static inner class. Static inner classes do not.

public class OuterClass {
    
    
    class InnerClass {
    
    
    }
    static class StaticInnerClass {
    
    
    }
    public static void main(String[] args) {
    
    
        // 在静态方法里,不能直接使用OuterClass.this去创建InnerClass的实例
        // 需要先创建OuterClass的实例o,然后通过o创建InnerClass的实例
        // InnerClass innerClass = new InnerClass();
        OuterClass outerClass = new OuterClass();
        InnerClass innerClass = outerClass.new InnerClass();
        StaticInnerClass staticInnerClass = new StaticInnerClass();

        outerClass.test();
    }
    
    public void nonStaticMethod() {
    
    
        InnerClass innerClass = new InnerClass();
        System.out.println("nonStaticMethod...");
    }
}

final

  1. If the basic data type is modified with final, it cannot be modified and is a constant; if the object reference is modified with final, the reference can only point to the object and cannot point to other objects, but the object itself can be modified.

  2. Final modified methods cannot be overridden by subclasses

  3. Final modified classes cannot be inherited.

this

this.属性名称Refers to accessing member variables in a class, which can be used to distinguish member variables from local variables. Access the variables of the current instance of the class Person as shown in the following code this.name.

/**
 * @description:
 * @author: 程序员大彬
 * @time: 2021-08-17 00:29
 */
public class Person {
    
    
    String name;
    int age;

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }
}

this.方法名称Used to access the methods of this class. In the following code, this.born()a method of the current instance of the class Person is called.

/**
 * @description:
 * @author: 程序员大彬
 * @time: 2021-08-17 00:29
 */
public class Person {
    
    
    String name;
    int age;

    public Person(String name, int age) {
    
    
        this.born();
        this.name = name;
        this.age = age;
    }

    void born() {
    
    
    }
}

super

The super keyword is used to access the variables and methods of the parent class in the subclass.

class A {
    
    
    protected String name = "大彬";

    public void getName() {
    
    
        System.out.println("父类:" + name);
    }
}

public class B extends A {
    
    
    @Override
    public void getName() {
    
    
        System.out.println(super.name);
        super.getName();
    }

    public static void main(String[] args) {
    
    
        B b = new B();
        b.getName();
    }
    /**
     * 大彬
     * 父类:大彬
     */
}

In the subclass B, we rewrite the method of the parent class . If we want to call the same method of the parent class in the getName()rewritten method, we must explicitly point it out through the super keyword.getName()

The difference between final, finally, finalize

  • final is used to modify attributes, methods, and classes, respectively indicating that attributes cannot be reassigned, methods cannot be overridden, and classes cannot be inherited.
  • finally is part of the exception handling statement structure, generally try-catch-finallyappearing in , and finallythe code block means that it is always executed.
  • finalize is a method of the Object class. This method is generally called by the garbage collector. When we call the System.gc()method, the garbage collector calls finalize()the method to recycle garbage. The JVM does not guarantee that this method is always called.

The role of the final keyword?

  • A final-modified class cannot be inherited.
  • Final modified methods cannot be overridden.
  • Variables modified by final are called constants. Constants must be initialized, and the value cannot be modified after initialization.

What is the difference between method overloading and overriding?

Multiple methods in the same class can have the same method name but different parameter lists, this is known as method overloading . The parameter list is also called the parameter signature, including the type of parameter, the number of parameters, and the order of parameters. As long as there is a difference, it is called a different parameter list.

Overloading is a fundamental feature of object-oriented.

public class OverrideTest {
    
    
    void setPerson() {
    
     }
    
    void setPerson(String name) {
    
    
        //set name
    }
    
    void setPerson(String name, int age) {
    
    
        //set name and age
    }
}

The rewriting of the method describes the relationship between the parent class and the child class. When the function of the parent class cannot meet the needs of the subclass, the method can be rewritten in the subclass . When a method is overridden, the method name and formal parameter list must be consistent.

In the following code, Person is the parent class, Student is the subclass, and the dailyTask method is rewritten in Student.

public class Person {
    
    
    private String name;
    
    public void dailyTask() {
    
    
        System.out.println("work eat sleep");
    }
}


public class Student extends Person {
    
    
    @Override
    public void dailyTask() {
    
    
        System.out.println("study eat sleep");
    }
}

What is the difference between an interface and an abstract class?

1. Differences at the grammatical level

  • Abstract classes can have method implementations, while interface methods can only have abstract methods (interface methods after Java 8 can have default implementations);
  • The member variables in the abstract class can be of various types, and the member variables in the interface can only be of public static final type;
  • Interfaces cannot contain static code blocks and static methods, while abstract classes can have static code blocks and static methods (interfaces can have static methods after Java 8);
  • A class can only inherit from one abstract class, but a class can implement multiple interfaces.

2. Differences at the design level

  • There are different levels of abstraction. An abstract class abstracts the entire class as a whole, including attributes and behaviors, but an interface only abstracts the behavior of a class. Inheriting an abstract class is a "whether" relationship, while interface implementation is a "whether there is" relationship. If a class inherits an abstract class, the subclass must be the type of the abstract class, and the interface implementation has relations that it does not have, such as whether birds can fly.
  • The class that inherits the abstract class has similar characteristics, but the class that implements the interface can be different.

Examples of doors and alarms:

class AlarmDoor extends Door implements Alarm {
    
    
    //code
}

class BMWCar extends Car implements Alarm {
    
    
    //code
}

What are the common exceptions?

Common RuntimeException:

  1. ClassCastException// type conversion exception
  2. IndexOutOfBoundsException//Array out of bounds exception
  3. NullPointerException//null pointer
  4. ArrayStoreException//Array storage exception
  5. NumberFormatException//Number formatting exception
  6. ArithmeticException//mathematical operation exception

checked Exception:

  1. NoSuchFieldException//reflection exception, no corresponding field
  2. ClassNotFoundException// class not found exception
  3. IllegalAccessException//The security permission is abnormal, it may be that the private method is called during reflection

The difference between Error and Exception?

Error : Serious problems that the JVM cannot solve, such as stack overflow StackOverflowError, memory overflow, OOMetc. An error that the program cannot handle.

Exception : Other general problems caused by programming errors or accidental external factors. Can be handled in code. Such as: null pointer exception, array subscript out of bounds, etc.

What is the difference between a runtime exception and a non-runtime exception (checked)?

unchecked exceptionIncluding RuntimeExceptionand Errorclasses, all other exceptions are called checked exceptions.

  1. RuntimeExceptionCaused by a program error, the program should be corrected to avoid such exceptions.
  2. checked ExceptionAn exception caused by a specific environment (the read file does not exist or the file is empty or sql exception). It must be processed, otherwise the compilation fails, you can catch or throws.

The difference between throw and throws?

  • throw : Used to throw a specific exception object.

  • throws : used in the method signature to declare the exceptions that the method may throw. The scope of exceptions thrown by subclass methods is even smaller, or no exceptions are thrown at all.

Tell NIO Clearly Through Stories

Let's explain it through an example.

Suppose a bank has only 10 employees. The bank's business process is divided into the following 4 steps:

1) The customer fills in the application form (5 minutes);

2) Staff review (1 minute);

3) The staff asks the security guard to withdraw money from the vault (3 minutes);

4) The clerk prints the receipt and returns the money and receipt to the customer (1 minute).

Let's take a look at how the different working methods of banks affect their work efficiency.

The first is the BIO method.

Every time a customer comes, it will be received and processed by a staff immediately, and this staff needs to be responsible for the above 4 complete processes. When there are more than 10 customers, the remaining customers need to wait in line.

It takes 10 minutes (5+1+3+1) for a clerk to process a customer. One hour (60 minutes) can handle 6 customers, a total of 10 staff, that is, only 60 customers can be processed.

It can be seen that the working status of the bank staff is not saturated. For example, in the first step, they are actually waiting.

This kind of work is actually BIO. Every time a request (customer) comes, it is allocated to the thread pool and processed by a thread (staff). If it exceeds the maximum limit of the thread pool (10), it is thrown into the queue and waits.

So how to improve the throughput of the bank?

The idea is: divide and conquer , split the tasks, and have specialized people be responsible for specialized tasks.

Specifically, the bank specially assigns a staff member A, whose job is to hand over a form for the customer to fill out whenever a customer comes to the bank. Whenever a customer fills out the form, A will randomly assign it to the remaining 9 staff members to complete the next steps.

In this way, assuming that there are a lot of customers, and the work of employee A is saturated, he will continue to bring the customers who have filled out the form to the counter for processing.

One employee at the counter can handle one customer in 5 minutes, and 9 employees can handle it in one hour: 9*(60/5)=108.

It can be seen that the transformation of the working style can bring about a great improvement in efficiency.

This way of working is actually the idea of ​​NIO.

The following figure is a very classic NIO illustration. mainReactorThe thread is responsible for listening to the server socket, receiving new connections, and assigning the established socket tosubReactor

subReactorIt can be a thread or a thread pool, which is responsible for demultiplexing connected sockets and reading and writing network data. The reading and writing of network data here can be compared to the time-consuming action of customers filling in forms. For specific business processing functions, it is thrown to the worker thread pool to complete.

You can see that a typical NIO has three types of threads, namely mainReactorthread, subReactorthread, and workthread.

Different threads do professional things. In the end, each thread is not empty, and the throughput of the system will naturally increase.

Is there any room for improvement in this process?

It can be seen that in the third step of this business process, the staff asked the security guard to withdraw money from the vault (3 minutes). These 3 minutes are spent by the counter staff while waiting, and these 3 minutes can be used.

It is still the idea of ​​​​divide and conquer, assigning a staff member B to be responsible for the third step.

Whenever the counter staff completes step 2, notify staff B to be responsible for communicating with the security guard to withdraw money. At this time, the counter staff can continue to process the next customer.

After employee B gets the money, he informs the customer that the money has arrived at the counter, and asks the customer to line up again. When the counter clerk serves the customer again, he finds that the customer has completed the first 3 steps, and can directly execute step 4.

In today's web services, it is often necessary to call third-party services through RPC or Http, which corresponds to step 3. If this step takes a long time, the resource usage rate can be greatly reduced through asynchronous methods.

The NIO+ asynchronous approach allows a small number of threads to do a large number of things. This applies to many application scenarios, such as proxy services, API services, long-term connection services, and so on. These applications will consume a lot of machine resources if they are synchronized.

However, although NIO+ asynchrony can improve system throughput, it cannot reduce the waiting time of a request, on the contrary, it may increase the waiting time.

In the end, the basic idea of ​​NIO can be summed up as follows: divide and conquer, split the tasks, and have dedicated people responsible for specific tasks

What is the difference between BIO/NIO/AIO?

Synchronous blocking IO : After the user process initiates an IO operation, it must wait for the actual completion of the IO operation before continuing to run.

Synchronous non-blocking IO : The client and the server are connected through a Channel, which is registered by multiplexer polling Channel. Improve throughput and reliability. After the user process initiates an IO operation, it can do other things, but the user process needs to poll whether the IO operation is completed, which causes unnecessary waste of CPU resources.

Asynchronous non-blocking IO : Non-blocking asynchronous communication mode, an upgraded version of NIO, uses asynchronous channels to realize asynchronous communication, and its read and write methods are asynchronous methods. The user process initiates an IO operation and then returns immediately. After the IO operation is actually completed, the application will be notified that the IO operation is completed. Similar to the Future pattern.

What is a daemon thread?

  • A daemon thread is a special process that runs in the background.
  • It is independent of the controlling terminal and periodically performs some task or waits for some event to occur.
  • Garbage collection threads are special daemon threads in Java.

Does Java support multiple inheritance?

In java, classes do not support multiple inheritance. Interfaces support multiple inheritance. The role of the interface is to extend the functionality of the object. When a sub-interface inherits multiple parent interfaces, it means that the sub-interface extends multiple functions. When a class implements this interface, multiple functions are extended.

Reasons why Java does not support multiple inheritance:

  • For security reasons, if multiple parent classes inherited by a subclass have the same method or property, the subclass will not know which one to inherit.
  • Java provides interfaces and inner classes to achieve multiple inheritance and make up for the defects of single inheritance.

How to achieve object cloning?

  • Implement Cloneablethe interface and override clone()the method . This method is a shallow copy, that is, if the attribute in the class has a custom reference type, only the reference is copied, and the object pointed to by the reference is not copied. If the Class of the property of the object also implements Cloneablethe interface , then the property will also be cloned when the object is cloned, that is, a deep copy.
  • Combining serialization, deep copy.
  • Object copying is done through org.apache.commonsthe utility classes in BeanUtilsand .PropertyUtils

The difference between synchronous and asynchronous?

Synchronous: When a call is made, the call does not return until the result is obtained.

Asynchronous: After the call is issued, the callee will notify the caller after returning the result, or process the call through a callback function.

What is the difference between blocking and non-blocking?

Blocking and non-blocking focus on the state of the thread.

A blocking call means that the current thread will be suspended before the result of the call is returned. The calling thread will not resume running until it has the result.

A non-blocking call means that the call will not block the current thread until the result cannot be obtained immediately.

For example, understand the difference between synchronous, blocking, asynchronous, and non-blocking:

Synchronization means boiling water, and you have to check whether it is on by yourself; asynchronous means that the water is boiling, and then the kettle rings to notify you that the water is boiling (callback notification). Blockage means that during the process of boiling water, you cannot do other things and must wait by the side; non-blocking means that you can do other things during the process of boiling water.

What are the new features of Java8?

  • Lambda expressions: Lambda allows functions to be passed as parameters of a method
  • Stream API: The newly added Stream API (java.util.stream) brings a true functional programming style to Java
  • Default method: A default method is a method that has an implementation in an interface.
  • Optional class: Optional class has become part of the Java 8 class library to handle null pointer exceptions.
  • Date Time API: Enhanced handling of dates and times.

Summary of new features in Java8

Serialization and deserialization

  • Serialization: The process of converting an object into a sequence of bytes is called serialization of an object.
  • Deserialization: The process of restoring a sequence of bytes to an object is called deserialization of the object.

When do you need to use serialization and deserialization?

When we only run the Java instance in the local JVM, there is no need for serialization and deserialization at this time, but when we need to persist objects in memory to disk or database, when we need to communicate with the browser When interacting, when we need to implement RPC, serialization and deserialization are required at this time.

Do the first two scenarios that require serialization and deserialization make us have a big question? When we interact with the browser and persist objects in memory to the database, it seems that There is no serialization and deserialization, because we have not implemented the Serializable interface, but it has been running normally.

The following conclusions are first given:

As long as we persist or network transfer objects in memory, serialization and deserialization are required at this time.

reason:

Is the Serializable interface really not used when the server interacts with the browser? The JSON format actually converts an object into a string, so the data format when the server interacts with the browser is actually a string. Let’s look at the String type source code:

public final class String
    implements java.io.Serializable,Comparable<String>,CharSequence {
    /\*\* The value is used for character storage. \*/
    private final char value\[\];

    /\*\* Cache the hash code for the string \*/
    private int hash; // Default to 0

    /\*\* use serialVersionUID from JDK 1.0.2 for interoperability \*/
    private static final long serialVersionUID = -6849794470754667710L;

    ......
}

The String type implements the Serializable interface and displays the value of the specified serialVersionUID.

Then let's look at the situation when the object is persisted to the database, the insert code in the Mybatis database mapping file:

<insert id="insertUser" parameterType="org.tyshawn.bean.User">
    INSERT INTO t\_user(name,age) VALUES (#{name},#{age})
</insert>

In fact, we do not persist the entire object to the database, but persist the properties in the object to the database, and these properties (such as Date/String) implement the Serializable interface.

Why implement the Serializable interface for serialization and deserialization?

After the Serializable interface is implemented in Java, the JVM will find that we have implemented this interface when the class is loaded, and then it will help us implement serialization and deserialization at the bottom when initializing the instance object.

If the type of the object to be written is not String, array, or Enum, and the Serializable interface is not implemented, a NotSerializableException will be thrown during serialization. The source code is as follows:

// remaining cases
if (obj instanceof String) {
    
    
    writeString((String) obj, unshared);
} else if (cl.isArray()) {
    
    
    writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
    
    
    writeEnum((Enum<?>) obj, desc, unshared);
} else if (obj instanceof Serializable) {
    
    
    writeOrdinaryObject(obj, desc, unshared);
} else {
    
    
    if (extendedDebugInfo) {
    
    
        throw new NotSerializableException(
            cl.getName() + "\n" + debugInfoStack.toString());
    } else {
    
    
        throw new NotSerializableException(cl.getName());
    }
}

After implementing the Serializable interface, why should the value of the specified serialVersionUID be displayed?

If the specified serialVersionUID is not displayed, the JVM will automatically generate a serialVersionUID according to the attribute during serialization, and then serialize together with the attribute, and then perform persistence or network transmission. When deserializing, the JVM will automatically generate a new version of serialVersionUID according to the attribute , and then compare this new serialVersionUID with the old serialVersionUID generated during serialization. If they are the same, the deserialization is successful, otherwise an error will be reported.

If the serialVersionUID is specified, the JVM will still generate a serialVersionUID during serialization and deserialization, but the value is the value we display, so that the old and new versions of the serialVersionUID will be consistent during deserialization.

If our class is not modified after it is written, there will be no problem if you do not specify serialVersionUID, but this is impossible in actual development. Our class will continue to iterate. Once the class is modified, the old object will be deserialized will report an error. So in actual development, we will specify a serialVersionUID explicitly.

Why are static properties not serialized?

Because serialization is for objects, static properties have priority over objects and are loaded with class loading, so they will not be serialized.

Seeing this conclusion, some people may ask, serialVersionUID is also modified by static, why serialVersionUID will be serialized? In fact, the serialVersionUID property is not serialized, JVM will automatically generate a serialVersionUID when serializing objects, and then we will display the specified The serialVersionUID attribute value is assigned to the automatically generated serialVersionUID.

What is the role of the transient keyword?

Java language keywords, variable modifiers, if an instance variable is declared with transient, its value does not need to be maintained when the object is stored.

That is to say, the value of the member variable modified by transient will be ignored during serialization. After deserialization, the value of the transient variable will be set to the initial value, such as 0 for int type and null for object type .

What is reflection?

The function of dynamically obtaining information and dynamically calling methods of objects is called the reflection mechanism of the Java language.

In the running state, for any class, you can know all the properties and methods of this class. For any object, you can call any of its methods and properties.

What are the application scenarios of reflection?

  1. When JDBC connects to the database, use Class.forName()the driver that loads the database through reflection
  2. Development tools such as Eclipse and IDEA use reflection to dynamically analyze the type and structure of objects, and dynamically prompt the properties and methods of objects
  3. serviceThe method of servlet is called by reflection in the web server
  4. The bottom layer of JDK dynamic proxy relies on reflection implementation

Tell me what is generic?

Java generics is a new feature introduced in JDK 5 that allows the use of type parameters when defining classes and interfaces. Declared type parameters are replaced with concrete types when used.

The biggest benefit of generics is that they can improve code reusability. Taking the List interface as an example, we can put String, Integer and other types into the List. If you don’t use generics, you need to write a List interface to store the String type, and write another List interface to store the Integer type. Generics are fine. to solve this problem.

How to stop a running thread?

There are several ways.

1. Use the stop method of the thread .

Use the stop() method to forcibly terminate the thread. However, stop is an obsolete method and is not recommended.

Using the Stop method will always propagate the ThreadDeath exception upwards, so that the target thread unlocks all locked monitors, that is, releases all object locks. The previously locked objects cannot be processed synchronously, which may cause data inconsistency.

2. Use the interrupt method to interrupt the thread . This method just tells the thread to terminate, but when it is finally terminated depends on the computer. Calling the interrupt method is just a stop mark in the current thread, not really stopping the thread.

Then call the Thread.currentThread().isInterrupted() method, which can be used to judge whether the current thread is terminated. Through this judgment, we can do some business logic processing. Usually, if isInterrupted returns true, an interrupt exception will be thrown, and then through try -catch Capture.

3. Set the flag bit

Set the flag bit, and when the flag bit is a certain value, the thread exits normally. Setting the flag is the way of using shared variables. In order to ensure the visibility of shared variables in memory, you can use volatile to modify it. In this way, the variable value will always get the latest value from the main memory.

But this volatile way of marking shared variables cannot complete the response when the thread is blocked. For example, after calling the Thread.sleep() method, the thread is in a non-running state. Even if the main thread modifies the value of the shared variable, the thread cannot check the loop flag at all at this time, so thread interruption cannot be realized.

Therefore, interrupt() plus manual exception throwing is currently the most correct way to interrupt a running thread .

What is cross domain?

Simply put, cross-domain refers to requesting resources from another domain name from a web page of one domain name. Due to the same-origin policy , such direct access is generally not allowed. However, many scenarios often require cross-domain access. For example, in the mode of separating the front and back ends, the domain names of the front and back ends are inconsistent, and cross-domain problems will occur at this time.

So what is the same-origin policy ?

The so-called homology means that "protocol + domain name + port" are the same, even if two different domain names point to the same IP address, they are not of the same origin.

The same-origin policy restricts the following behaviors:

1. Cookie、LocalStorage 和 IndexDB 无法读取
2. DOM 和 Js对象无法获得
3. AJAX 请求不能发送

Why is there a same-origin policy ?

For example, if you have just entered your account password in online banking, checked your balance, and then visited other colored websites, this website can access the online banking site just now and obtain the account password, then the consequences can be imagined. Therefore, from a security point of view, the same-origin policy is conducive to protecting website information.

How to solve the cross-domain problem?

Well, there are several ways:

CORS , Cross-Origin Resource Sharing

CORS (Cross-origin resource sharing), cross-origin resource sharing. CORS is actually a specification formulated by the browser. The browser will automatically communicate with CORS. Its implementation is mainly on the server side. Some HTTP Headers are used to limit the domains that can be accessed. For example, page A needs to access the data on the B server. If B The server declares that the domain name of A is allowed to access, then the cross-domain request from A to B can be completed.

@CrossOrigin annotation

If the project uses Springboot, you can add a @CrossOrigin(origins="*") annotation to the Controller class to achieve cross-domain access to the current controller. Of course, this tag can also be added to the method, or directly added to Cross-domain processing is performed on all interfaces on the entry class. Note that the version of SpringMVC supports @CrossOrigin only in version 4.2 or above.

Nginx reverse proxy interface cross-domain

The principle of cross-domain nginx reverse proxy is as follows: First, the same-origin policy is the security policy of the browser, not part of the HTTP protocol. The server calls the HTTP interface only using the HTTP protocol, does not execute JS scripts, does not require the same-origin policy, and there is no crossing problem.

The cross-domain implementation of the nginx reverse proxy interface is as follows: configure a proxy server (the domain name is the same as domain1, and the port is different) through nginx as a springboard, and the reverse proxy accesses the domain2 interface, and can modify the domain information in the cookie by the way, which is convenient for the current domain cookie Write to realize cross-domain login.

// proxy服务器
server {
    
    
    listen       81;
    server_name  www.domain1.com;
    location / {
    
    
        proxy_pass   http://www.domain2.com:8080;  #反向代理
        proxy_cookie_domain www.domain2.com www.domain1.com; #修改cookie里域名
        index  index.html index.htm;
        
        add_header Access-Control-Allow-Origin http://www.domain1.com;
    }
}

In this way, our front-end agent only needs to visit http:www.domain1.com:81/*.

Cross-domain through jsonp

Usually, in order to reduce the load on the web server, we separate static resources such as js, css, and img to another server with an independent domain name, and then load static resources from different domain names through corresponding tags in the html page. Allowed operations, based on this principle, we can dynamically create scripts and then request a URL with parameters to achieve cross-domain communication.

What should be paid attention to when designing the interface?

  1. Interface parameter verification . The interface must verify parameters, such as whether the input parameter is allowed to be empty, and whether the length of the input parameter meets the expectation.
  2. When designing an interface, fully consider the scalability of the interface . Think about whether the interface can be reused, and how to maintain the scalability of the interface.
  3. Consider changing serial calls to parallel calls . For example, to design a mall home page interface, you need to check product information, marketing information, user information, and so on. If it is serially checked one by one, it will take a lot of time. This scenario can be changed to parallel calls to reduce the time-consuming interface.
  4. Whether the interface needs anti-heavy processing. When it comes to database modification, anti-duplication processing should be considered, and the database anti-duplication table can be used, with the unique serial number as the unique index.
  5. The log is printed comprehensively , the input and output parameters, the interface is time-consuming, the log is recorded well, and it is convenient to dump the pot.
  6. When modifying old interfaces, pay attention to compatibility design .
  7. Exceptions are handled properly . Use finally to close stream resources, use log printing instead of e.printStackTrace(), don't swallow exceptions, etc.
  8. Whether current limiting needs to be considered . Current limiting is used to protect the system and prevent traffic peaks from exceeding the carrying capacity of the system.

What is the difference between filter and interceptor?

1. The implementation principles are different .

The underlying implementations of filters and interceptors are different. Filters are based on function callbacks, and interceptors are implemented based on Java's reflection mechanism (dynamic proxy). Generally, a custom filter will implement a doFilter() method, which has a FilterChain parameter, but in fact it is a callback interface.

2. The scope of use is different .

The filter implements the javax.servlet.Filter interface, and this interface is defined in the Servlet specification, which means that the use of the filter depends on containers such as Tomcat, so it can only be used in web programs. The interceptor is a Spring component and is managed by the Spring container. It does not depend on containers such as Tomcat and can be used alone. Interceptors can be used not only in web programs, but also in programs such as Application and Swing.

3. Different scenarios are used .

Because the interceptor is closer to the business system, the interceptor is mainly used to realize the business judgment in the project, such as: logging, authority judgment and other businesses. Filters are usually used to implement general-purpose functional filtering, such as sensitive word filtering, response data compression, and other functions.

4. The trigger timing is different .

Filter Filter is preprocessed after the request enters the container, but before entering the servlet, and the end of the request is after the servlet is processed.

The Interceptor is preprocessed after the request enters the servlet and before entering the Controller, and the request ends after the corresponding view is rendered in the Controller.

5. The range of intercepted requests is different .

The execution order of the request is: the request enters the container -> enters the filter -> enters the Servlet -> enters the interceptor -> executes the controller. It can be seen that the execution timing of the filter and the interceptor is also different. The filter will be executed first, then the interceptor will be executed, and finally the actual method to be called will be entered.

Reference link: https://segmentfault.com/a/1190000022833940

What should be considered when connecting to third-party interfaces?

Well, here are a few things to consider:

  1. Confirm that the network protocol connected to the interface is https/http or a custom private protocol.
  2. Agree on data transfer parameters and response formats (such as application/json), and pay special attention when connecting weak types to strongly typed languages
  3. In terms of interface security , it is necessary to determine the identity verification method, use token, certificate verification, etc.
  4. Confirm whether a retry mechanism is required after the interface call fails to ensure the final consistency of data transmission.
  5. Logging should be comprehensive . The interface input and output parameters, as well as the parameter values ​​after analysis, must be recorded in logs to facilitate the positioning of problems (throwing the pot).

Reference: https://blog.csdn.net/gzt19881123/article/details/108791034

What are the methods for backend interface performance optimization?

There are the following methods:

1. Optimize the index . Add an index to the key field of the where condition, or order bythe subsequent sorting field.

2. Optimize the sql statement . For example, avoid using select *, batch operations, avoid deep paging, improve the efficiency of group by, etc.

3. Avoid big things . Using @Transactional to annotate this declarative transaction to provide transaction functions can easily cause large transactions and cause other problems. You should avoid processing too much data at one time in a transaction, and put some logic that has nothing to do with the transaction outside the transaction.

4. Asynchronous processing . Separate the main logic and auxiliary logic, the auxiliary logic can be executed asynchronously, and the library can be written asynchronously. For example, when the goods purchased by the user are delivered, a text message notification needs to be sent. The text message notification is a secondary process and can be executed asynchronously so as not to affect the execution of the main process.

5. Reduce the lock granularity . In a concurrent scenario, multiple threads modify data at the same time, resulting in data inconsistency. In this case, it is generally solved by locking. However, if the lock is not added properly, the granularity of the lock will be too coarse, which will greatly affect the performance of the interface.

6. Add cache . If the amount of data in the table is very large, the performance will be very poor if the data is directly queried from the database. You can use Redis memcached to improve query performance, thereby improving interface performance.

7. Sub-database and sub-table . When the system develops to a certain stage, there will be a large number of concurrent users, and there will be a large number of database requests, which will occupy a large number of database connections, and will also cause disk IO performance bottlenecks. Or the database table data is very large, even if the SQL query uses the index, it is time-consuming. At this time, it can be solved by sub-database sub-table. The sub-library is used to solve the problem of insufficient database connection resources and the performance bottleneck of disk IO. Table division is used to solve the problem that the amount of data in a single table is too large, and it is very time-consuming to query data with SQL statements, even if the index is used.

8. Avoid querying the database in a loop . It is very time-consuming to query the database in a loop. It is best to get all the required data in one query.

Why is it mandatory to use wrapper type to define attributes in Alibaba Java Development Manual?

Well, taking the Boolean field as an example, when we do not set the value of the field of the object, the variable of type Boolean will set the default value null, and the variable of type boolean will set the default value false.

That is to say, the default value of the package type is null, while the default value of the basic data type is a fixed value, such as false for boolean, 0 for byte, short, int, long, and 0.0f for float.

To give an example, for example, there is a fee deduction system that needs to read a rate value from an external pricing system when deducting fees. We expect that the return value of this interface will contain a floating-point rate field. When we get this value, we use the formula: amount * rate = fee to calculate, and the calculation result is deducted.

If the billing system is abnormal, it may return a default value. If the field is of Double type, the default value is null, and if the field is of double type, the default value is 0.0.

If the deduction system does not do special processing for the return value of the rate, it will directly report an error and block the program if it gets a null value for calculation. If you get 0.0, you may directly calculate it, and after the interface is 0, you will deduct the fee. This abnormality cannot be perceived.

Then I can make a special judgment on 0.0. If it is 0, I will block the error report. Is this possible?

No, a problem will arise at this time, how to deal with the scene where the allowed rate is 0?

Using basic data types will only make the solution more and more complicated, with more and more pitfalls.

This way of defining variables using wrapper types blocks the program through exceptions, and then can be identified to this kind of online problem. If the basic data type is used, the system may not report an error, and then consider that there is no exception.

Therefore, it is recommended to use wrapper types in return values ​​of POJOs and RPCs.

Reference link: https://mp.weixin.qq.com/s/O_jCxZWtTTkFZ9FlaZgOCg

8 ways to improve interface performance by 100 times

pooling thought

If you create a thread every time you need to use it, it will take a certain amount of time, and the thread pool can reuse threads to avoid unnecessary time-consuming.

For example, TCPthe three-way handshake, which is introduced in order to reduce performance loss, Keep-Alive长连接avoids frequent creation and destruction of connections.

deny blocking wait

If you call a system B's interface, but it handles business logic, time-consuming needs 10seven more. Then do you block and wait until the downstream interface of system B returns , and then continue your next operation? This is obviously unreasonable .

Refer to the IO multiplexing model . That is, we don't need to block Bthe interface of the waiting system, but do other operations first. After Bthe interface of the system is processed, through the event callback notification, our interface receives the notification and then performs the corresponding business operation.

Remote calls changed from serial to parallel

For example, to design a mall home page interface, you need to check product information, marketing information, user information, and so on. If it is serially checked one by one, it will take a lot of time. This scenario can be changed to parallel calls to reduce the time-consuming interface.

Lock granularity to avoid too coarse

In high concurrency scenarios, in order to prevent overselling and other situations , we often need to lock to protect shared resources . However, if the locking granularity is too coarse, it will greatly affect the performance of the interface.

Regardless of whether you are synchronizedlocking or redisdistributed locking, you only need to lock shared critical resources. If shared resources are not involved, locking is not necessary.

Time-consuming operation, consider putting it into asynchronous execution

For time-consuming operations, consider using asynchronous processing , which can reduce the time-consuming interface. For example, after the user registers successfully, SMS and email notifications can be processed asynchronously.

use cache

Put the data to be checked into the cache in advance, and check the cache directly when needed, avoiding the process of checking the database or calculation .

Initialize to cache in advance

The idea of ​​prefetching is easy to understand. It is to initialize the data to be calculated and queried to the cache in advance . If you need to use complexly calculated data at a certain time in the future to calculate in real time, it may take a long time . At this time, we can adopt the idea of ​​prefetching, calculate the data that may be needed in the future in advance, put it in the cache , and fetch it from the cache when needed. This will greatly improve interface performance.

Compressed content for transmission

Compress the transmission content, the transmission message becomes smaller, so the transmission will be faster.

Finally, I would like to share with you a Github repository, which has more than 300 classic computer book PDFs compiled by Dabin, including C language, C++, Java, Python, front-end, database, operating system, computer network, data structure and algorithm, machine learning , programming life , etc., you can star it, next time you look for a book directly search on it, the warehouse is continuously updated~

Github address

Guess you like

Origin blog.csdn.net/Tyson0314/article/details/130836561