Interviewer: Do you know what a Java class is? sorry sir, I don’t know what Java is tired

Recently, I encountered a more interesting question when brushing the interview questions. The details are as follows.
Insert picture description here
I’m sorry, the picture is wrong, the following is

class SingleTon {
    private static SingleTon singleTon = new SingleTon();
    public static int count1;
    public static int count2 = 0;
 
    private SingleTon() {
        count1++;
        count2++;
    }
 
    public static SingleTon getInstance() {
        return singleTon;
    }
}
 
public class Test {
    public static void main(String[] args) {
        SingleTon singleTon = SingleTon.getInstance();
        System.out.println("count1=" + singleTon.count1);
        System.out.println("count2=" + singleTon.count2);
    }
}

In order to better understand its underlying principles, I must not review and sort out Java's class loading mechanism.

When to load the class

A class starts from being loaded into the virtual machine's memory until it is unloaded from the memory. Its entire life cycle includes: loading, verification, preparation, analysis, initialization, use and unloading these 7 stages. Among them, the three parts of verification, preparation and analysis are collectively called linking .
Insert picture description here

Among them, the order of the five stages of loading, verification, preparation, initialization, and unloading is determined. The loading process of the class must be "started" step by step in this order (only refers to the beginning, not the execution or the end, because these The phases are usually intersected and mixed, and usually call or activate another phase during the execution of one phase, while the parsing phase is not necessarily (it can start after the initialization phase in some cases. This is In order to support the runtime binding of the Java language.

When to start class initialization

Under what circumstances need to start the first stage of the class loading process: "loading". There is no mandatory constraint in the virtual machine specification. This can be left to the specific implementation of the virtual machine. However, the virtual machine specification strictly stipulates the following conditions for the initialization phase. If the class is not initialized, the class will be initialized.
1. Create an instance of the class

2. Access to static variables of the class (except constants [static variables rhetorically finalized] Reason: Constants are a special kind of variable, because the compiler treats them as values ​​instead of fields. If you A constant variable is used in the code, and the compiler does not generate bytecode to load the value of the domain from the object, but directly inserts this value into the bytecode. This is a very useful Optimize, but if you need to change the value of the final domain, then every piece of code that uses that domain needs to be recompiled.

3. Access the static method of the class

4. Reflection such as (Class.forName("my.xyz.Test"))

5. When initializing a class, it is found that the parent class has not yet been initialized, then the initialization of the parent class is started first

6. When the virtual machine starts, the class that defines the main() method is initialized first

The above situation is called " active reference " to a class . Except for this situation, the initialization of the class will not be triggered. The loading process of the interface called " passive reference "
is slightly different from the loading process of the class. The static{} block cannot be used in the interface. When an interface is initialized, it is not required that all its parent interfaces have been initialized. Only when the parent interface is actually used (for example, constants defined in the reference interface) will it be initialized.

Passive reference example

1. The subclass calls the static variable of the parent class, and the subclass will not be initialized. Only the parent class is initialized. . For static fields, only the class that directly defines this field will be initialized.

2. Referencing the class through the array definition will not trigger the initialization of the class

3. Access to class constants will not initialize the class

class SuperClass {
    static {
        System.out.println("superclass init");
    }
    public static int value = 123;
}
 
class SubClass extends SuperClass {
    static {
        System.out.println("subclass init");
    }
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(SubClass.value);// 被动应用1
        SubClass[] sca = new SubClass[10];// 被动引用2
    }
}

The output of the program is
superclass init
123.

The input results above prove that passive reference 1 and passive reference 2

class ConstClass {
    static {
        System.out.println("ConstClass init");
    }
    public static final String HELLOWORLD = "hello world";
}
 
public class Test {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLOWORLD);// 调用类常量
    }
}

The program output
hello world
from the above output proves passive reference 3

Class loading process

1. Load

The "Loading" phase is the first phase of the "Class Loading" process. In this phase, the virtual machine needs to complete the following three things:

1. Obtain the binary byte stream that defines this class through the fully qualified name of a class.

2. Convert the static storage structure represented by this byte stream into the runtime data structure of the method area.

3. Generate a java.lang.Class object representing this class in the Java heap as the access entry for these data in the method area.

The loading stage can be completed by using the class loader provided by the system, or by a user-defined class loader. Part of the content of the loading phase and the connection phase (such as a part of the bytecode file format verification action) are carried out alternately. The loading phase has not been completed, and the connection phase may have begun.

2. Verification

Verification is the first step in the connection phase. The purpose of this phase is to ensure that the information contained in the byte stream of the Class file meets the requirements of the current virtual machine and does not endanger the security of the virtual machine itself.

The Java language itself is a relatively safe language. It is impossible to use Java coding to access data outside the boundary of an array, transform an object into a type that it does not implement, etc. If this is done, the compiler will refuse to compile. However, the Class file is not necessarily compiled from the Java source code. Any method can be used, including direct writing with a hexadecimal editor (such as UltraEdit). If harmful "code" (byte stream) is written directly, and the virtual machine does not check when loading the class, it may endanger the security of the virtual machine or program.

Different virtual machines may have different implementations of class verification, but generally they will complete the following four phases of verification: file format verification, metadata verification, bytecode verification, and symbol reference verification.

1. File format verification is to verify whether the byte stream complies with the Class file format specification and can be processed by the current version of the virtual machine. For example, verify whether the magic number is 0xCAFEBABE; whether the major and minor version numbers are within the processing range of the current virtual machine; whether there are unsupported constant types in the constant pool constants... The main purpose of the verification phase is to ensure the input byte stream It can be parsed correctly and stored in the method area. After verification at this stage, the byte stream will be stored in the method area of ​​the memory, so the following three verification stages are based on the storage structure of the method area.

2. Metadata verification is to perform semantic analysis on the information described by bytecode to ensure that the information described meets the requirements of the Java language specification. May include verification such as: whether this class has a parent class; whether the parent class of this class inherits a class that is not allowed to be inherited; if this class is not an abstract class, whether it implements all the methods required to be implemented in its parent class or interface... …

3. Bytecode verification. The main work is to analyze data flow and control flow to ensure that the method to be verified will not perform behaviors that endanger the security of the virtual machine during operation. If the bytecode of a class method body fails the bytecode verification, then there must be a problem; but if a method body passes the bytecode verification, it does not mean that it must be safe.

4. Symbol reference verification occurs when the virtual machine converts the symbol reference into a direct reference. This conversion action will occur in the "analysis phase". Verify whether the corresponding class can be found by the permission name described by the character string in the symbol reference; whether there is a descriptor that matches the method field and the method and field described by the simple name in the specified class; the class, field and method in the symbol reference Whether accessibility (private, protected, public, default) can be accessed by the current class

The verification phase is not necessarily a necessary phase for the class loading mechanism of the virtual machine. If all the code is running to confirm it is safe, you can use -Xverify: none parameter to shut down most of the class verification measures to reduce virtual machine class load time.

3 Preparation

The preparation phase is to allocate memory for the static variables of the class and initialize them to default values. These memory will be allocated in the method area. The preparation phase does not allocate memory for instance variables in the class. The instance variables will be allocated in the Java heap along with the object when the object is instantiated.

public static int value=123;//In the preparation phase, the initial value of value is 0. It will become 123 in the initialization phase.

4 Analysis

The parsing phase is a process in which the virtual machine replaces the symbol references in the constant pool with direct references.

Symbolic Reference: A symbolic reference uses a set of symbols to describe the referenced target. The symbol can be any form of literal, as long as it can be used to locate the target without ambiguity. The symbolic reference has nothing to do with the memory layout implemented by the virtual machine, and the referenced target is not necessarily loaded into the memory.

Direct Reference: A direct reference can be a pointer that directly points to the target, a relative offset, or a handle that can indirectly locate the target. Direct reference is related to the memory layout implemented by the virtual machine. If there is a direct reference, then the referenced target must already exist in memory.

5 Initialization

Class initialization is the last step of the class loading process. In the previous class loading process, the user application can participate in the loading stage through a custom class loader, and the rest of the actions are completely dominated and controlled by the virtual machine. At the initialization stage, the Java program code defined in the class is actually executed.

The initialization phase is the process of executing the class constructor () method. () Method by the compiler from assigning class collection operation moving all classes and static variables block of statements (static {} block) merge statements generated.

Topic analysis

By re-interpreting the loading timing of the class and the loading process of the class, and then we interpret the previous topic through the above theory

class SingleTon {
    private static SingleTon singleTon = new SingleTon();
    public static int count1;
    public static int count2 = 0;
 
    private SingleTon() {
        count1++;
        count2++;
    }
 
    public static SingleTon getInstance() {
        return singleTon;
    }
}
 
public class Test {
    public static void main(String[] args) {
        SingleTon singleTon = SingleTon.getInstance();
        System.out.println("count1=" + singleTon.count1);
        System.out.println("count2=" + singleTon.count2);
    }
}

Draw the following analysis conclusions:

1:SingleTon singleTon = SingleTon.getInstance(); Called the SingleTon of the class and called the static method of the class, triggering the initialization of the class

2: When the class is loaded, memory is allocated for the static variables of the class during the preparation process and the default value is initialized singleton=null count1=0, count2=0

3: Class initialization, assign values ​​to static variables of the class and execute static code faster. Singleton assignment is new SingleTon() calls the constructor of the class

4: after calling the constructor of the class count=1; count2=1

5: Continue to assign values ​​to count1 and count2, at this time count1 has no assignment operation, all count1 is 1, but count2 performs the assignment operation and becomes 0

Final summary

Insert picture description hereSince the current market environment is changing, it is definitely not enough to simply brush the interview questions, so you need to know more about the underlying knowledge of JAVA, you can pay attention to my public account: Java Development Road , learn more JAVA dry goods knowledge and information.

Guess you like

Origin blog.csdn.net/Lubanjava/article/details/108199729