Detailed class loading process

Class loading process:

    In Java ClassLoader (abstract class) of the main responsibilities of the various class is responsible for loading the file into the JVM, generate a variety of data structures of the class, and then distributed to the corresponding JVM memory area.

The class loading process is generally divided into three phases: loading phase, the connection phase (verification, preparation, analysis), the initialization phase.

1. Load stages: the main responsible for finding and binary data file (class file) to load the class

2. Connect phases: the connection phase to do more, divided into three stages:

  1. Verification: mainly to ensure the correctness of the file, such as class version, class of magic factor is correct
  2. Preparation: allocate memory for static variables of the class, and to their initialization defaults
  3. Analysis: The class is converted into direct reference symbol references

3. initialization phase: given the correct initial value of a static variable class (given the preparation stage of the value code)

Used actively used and are read class:

    JVM virtual machine specification for each class or interface is a Java program for the first time will take the initiative to use its initialization, of course, with the JIT technology is mature, do not rule out an initialization JVM predict in advance all kinds during operation.

    6 while the JVM specification used in the active category scene, as follows:

  1. By the new keyword cause class initialization
  2. Access static variables
  3. Access class static method
  4. Reflects the operation class
  5. Initialization subclass also cause the parent class is initialized (subclass. Property without causing parent class initialization sub)
  6. Startup Class Execution main function
//父类
public class demo2 {

    public static int num = 20;

    static{
        System.out.println ("我是静态代码块demo2");
    }

    static void test(){
       System.out.println ("我是静态方法demo2");       
    }
}
//子类
public class demo2_son extends demo2{

    public static int num_son;

    public demo2_son() {
        System.out.println ("demo2_son的构造方法");
    }

    static {
        System.out.println ("demo2_son的静态代码块");
    }
}

//测试类
public class test {

    public static void main(String[] args) {
        //2:访问类的静态变量导致类的初始化
        System.out.println (demo2.num);//我是静态代码块demo2     20
        //3:访问类的静态方法导致类的初始化
         demo2.test();//我是静态代码块demo2    我是静态方法demo2
        //4:对某个类进行反射操作
         Class.forName ("AtomicIntegerTest.demo2");//我是静态代码块demo2
        //初始化子类导致父类初始化
        System.out.println (demo2_son.num_son);//我是静态代码块demo2     demo2_son的静态代码       0
        System.out.println (demo2_son.num);//我是静态代码块demo2     20  不会导致父类的初始化

        //6:启动类:执行main喊函数所在类
 
    }

}

In addition to the above case 6, and the rest are called passive use, it does not lead to load and initialize the class, active and passive about classes where there are several confusing:

  1. An array structure of a class does not cause class initialization: Simple [] sp = new Simple [10]; not because they think the initiative to use the keyword new, just opened up in the heap memory address space for a continuous 4bytex10
  2. Static const reference to the class does not cause class initialization: If demo2_son num instead of a static constant, direct access to such will not be loaded in the other class (parent class Kenken not given)

First look at a case, step by step how to enter the class is loaded:

public class Singleton {
    private static int x = 0;
    private static int y;
    private static Singleton singleton = new Singleton ();//此处移到最上面,结果又如何?

    private Singleton(){
        x++;
        y++;
        System.out.println ("构造");
    }

    public static Singleton getInstance(){
        return singleton;
    }

    public static void main(String[] args) {
        Singleton singleton = Singleton.getInstance ();
        System.out.println (singleton.x);
        System.out.println (singleton.y);
    }

}

How about the results, why not the same?

Class loading phase:

Briefly class loading binary data is read class files into memory, the static storage structure represented by the byte stream into a data structure and method of operation when the zone, and generating a class in the heap memory java.lang.Class object access method most data structure entry, as in FIG.

The final product is a class load heap memory class object, the same ClassLoder terms. No matter how many times a class is loaded, the corresponding heap memory is always a class object, and we are talking about here is the first phase of class loading, it does not represent the entire class loading is complete.

Class connection phase:

    ① Verification:

Verify the connection phase main purpose is to ensure that the content of the byte stream information contained in the class file with current regulatory requirements, jvm, when the information does not meet the requirements of the byte stream VerifyError exception will be thrown, or a subclass, verification the information content of the following aspects

(1) verify that the file format:

  1. In many binary files, the file header exists magic factor that determines which types of files, file pieces of magic factor class: 0xCAFEBABE
  2. The major version number, java version number is constantly upgraded, jvm specification is also constantly upgrading say, for example, you make good use of jdk compiled version of the class can not be compatible with earlier versions of jvm. In the verification process will see the current class file version meets the scope of the current jdk processed
  3. Constitute a class file byte stream or whether there are other additional information incomplete, mainly to see the class of MD5 fingerprint (each class at compile time after the MD5 algorithm will digest the results are to class byte stream, as part of a stream of bytes )
  4. Constants pool if there is a variable type is not supported, such as int64
  5. Whether the reference point is constant refers to the constant type constant or absence of change is not supported

Of course, verification of class jvm byte stream is far more than that, due to the wide variety of sources to obtain class byte stream, or even write a binary byte stream according to jvm specification, validation of file formats can be initialized in the class before some of the non-compliant, malicious byte shut, verify that the file format is equivalent to pioneer levels.

(2) verification of metadata:

  1. This class checks whether there is a parent class, whether inherited an interface, whether these parent classes and interfaces legitimate or whether it is real.
  2. Check whether the class inherits the final modified class, modified final class is not allowed to be inherited and in which the method is to be allowed to override the
  3. Check whether the class is an abstract class, if not an abstract class, whether it implements the abstract methods of the parent class or interface in all methods
  4. Checking the legality of overloaded methods, such as the same method name, the same parameters, but returns the different types that are not allowed
  5. Other syntax validation

(3) bytecode verification:

Asking price has elapsed and metadata Authentication bytecode verification will be verified, this portion is more complex, authentication is the main control flow of the program such as loops, branching, etc.

  1. To ensure that the current thread in the instruction program counter does not jump to the unlawful bytecode instructions to go
  2. Ensure valid when the type of conversion, such as A statement by reference, can not be cast conversion (translation exception) with B
  3. Any time to ensure that the virtual machine stack type instruction code can be correctly performed, such as when an incoming push type A is a reference, when using the type B loaded to shift to the local variable table
  4. Other verification

(4) Verify reference symbol

We said during the loading of the class, some may cross the stage is running, such as early stage before the load is not over yet, the connection phase may start to work, the benefits of doing so is to increase efficiency, the same symbol reference conversion is to verify the symbol when referring to the conversion of a direct reference to the legitimacy

  1. It defines whether the name string described by reference symbol to find related classes
  2. Whether symbolic reference in the classes, fields, methods, visible to the current class, you can not access private methods such as reference to the class
  3. other

The purpose of verification reference symbols are resolved to ensure the smooth implementation of actions, such as certain kinds of if the field does not exist. Will throw NoSuchFileError, if the method does not exist then climbed out NoSuchMethodError, etc., we will encounter such information at the time of reflection

② preparation

When a class byte stream passed all the verification process, starts distribution of class variables (static variables) class object memory, and sets the initial value of the class variable memory area is allocated to a method, different from the actual variable will be assigned into the heap memory, called the initial set value, in fact, the corresponding class variable of a given type of a correlation value when there is no default setting value, the initial value of the different types of data in Table:

type of data

 

Byte

(byte)0

Char

'\ U0000'

Short

(short)0

Int

0

Float

0.0F

Long

0L

Boolearn

false

Reference types

null

Setting an initial value of a class variable code is as follows: public class Demo {private static int a = 10; private static final int b = 20;} wherein a is 0 rather than 10 in the preparation phase, and b is 20 in the preparation phase, as static const does not cause class initialization, is a passive reference, so you would not exist connection phase, of course, more rigorous argument is b class compilation phase will generate the value of its properties directly generate ConstValue given 20

③ resolve

       During parsing class will still be used in some of the cross-validation process, such as symbol validation is to find the so-called resolve symbolic references classes, interfaces, fields and methods in the constant pool and replace the reference symbols directly referenced process:

public class Test{
    static Simple simple = new Simple();
    public static void main(String[] args){
        System.out.println(simple);
    }
}

       The above code uses Simple class, when writing programs we can use this simple direct reference to access it visible methods and properties, but not so simple in the class bytecode, it will be compiled into a corresponding mnemonic these mnemonic become symbolic references, during parsing class, mnemonics need further resolved to find the correct Simple data structure heap memory. The following is a bytecode Test pieces of information:

       Get PringtStrean and Simple instructions in the constant pool by getstatic, then passed to the println method of PrintStream, during the execution of the bytecode need to be resolved before being executed by invokvirtual getstatic instruction. VM provides, anewarray, checkcast, getfield, getstatic, instanceof, invokeinterface, invokespecial, invokevirtual, before bytecode multianewarray, new, putfield, putstatic this 13 operation symbolic references must be resolved in advance for all the symbols. Mainly for parsing class interface, fields, methods, and classes for these four interface method, corresponding to the constant pool CONSTANT_Class_info, CONSTANT_Field_info, Constant_Methodref_info constant, and these four types Constant_InterfaceMethodred_info

Class interface Resolution:

  1. Suppose foregoing Simple code is not an array type, in the loading process, the need to complete the loading of the Simple class, the class also need to go through all the stages of loading
  2. If an array type is simple, it is not required to complete the loading of the virtual machine is simple, only need to generate a representative of the types of data objects in a virtual machine, and open up a contiguous address space in the heap memory
  3. After completion of parsing class interface requiring verification of symbolic references

Field analysis:

    The so-called field parsing is your class or interface to access the fields, and parsing class or variable, if the field does not exist or an error occurs, it will not be thrown following resolution

  1. If a simple class itself contains a field, simply return a reference to this field, of course, also belongs to the class of the field early in advance of the class loader
  2. If the class itself is simple package without a field, according to the inheritance will be bottom-up or find the parent class field interface, you can find return, also need to be ahead of the field to find the class loading process
  3. If Simple is not a class field, Object has been found or not, it means that the lookup fails, there is no longer any resolution, direct throw NoSuchFidldError abnormal (reflecting experience)

     This explains why the subclass overrides reason after the parent class of the field can enter into force, because it has found a field directly initialized and returned (bottom-up look: do not themselves have to continue to look up a)

Analytical methods class: class methods and interfaces are different methods, class methods can be called using the class directly, but must have the appropriate interface method inherited classes to be able to call

  1. If it is found in the class method table index Simple class_index in an interface rather than a class, directly returns an error.
  2. Find Simple class method if there is exactly the same method described methods and goals, there is a direct returns a reference to this method, if any, continue to look up.
  3. If the parent class is still not found, it means that the lookup fails, the program throws an exception NoSuchMethodError.
  4. If the current class or parent class method to find the target and consistent method, but it is an abstract method, an exception is thrown AbstractMethodError.

    In the process of finding, there have been a lot of checking and verification.

Interface analytic approach: not only can define an interface method, you can also inherit other interfaces

  1. Class_index found in the index is a simple class rather than an interface, it will directly return an error, because the method and type of class interface interface table table should be accommodated it is not the same in the interface method, which is why it is necessary in the constant pool Constant_Methodef_info and have two different types Constant_InterfaceMethodred_info
  2. The next method to find and compare similar analytical methods, and bottom-find, or not find an exception is thrown NosuchMethodError

Class initialization:

     After a series of hurdles finally came to the initialization phase class, class initialization phase is the last stage of the entire class loading process, do the initialization phase the most important thing is to execute the process <clinit> () method, which is literally the implication is class initialize, at <clinit> () method in all class variables are assigned the correct value, which is the value specified in the preparation of the program.

     <clinit> () method is generated during the compilation phase, which means it is already included in the class file, the method includes all assignment operation class variables and perform a static code block code sequence is performed by the compiler to collect statements appear (method <clinit> () to ensure sequential) order determined in the source file, another point to note is that the static statements can only block on the back of a static variable assignment, but can not access it. Otherwise unable to compile, it is only responsible for the assignment and perform static code block

public class StaticTest {

    static {
        System.out.println (x);//x = 20  
    }
    private static int x = 10;


}

     In addition <clinit> () constructor method of the class is different, it does not display the constructor calls the parent class, the virtual guarantee of the parent class <clinit> () method is executed first, so the parent class static variable total It was able to get priority assignment

public class StaticTest {

    //父类中定义类变量
    static class Parent{
        static int value = 1;
        static{
            value = 2;
            System.out.println ("父类代码块");
        }
    }
    //子类使用父类的静态变量为自己的静态变量赋值
    static class Child extends Parent{
        static int val = value;

    }

    public static void main(String[] args) {
        System.out.println (Child.val);//2
    }
}

      The above program output is 2 instead of 1, because the parent class <clinit> () method priority has been implemented, although the Java compiler will help generate class <clinit> () method, but this method is not always generated, For example, a class is not static block of code and static variables, then he would not generate this method, the interface is also true, because the interface can not define a natural static code block, in order to generate this method only when the interface has a variable initialization.

       <Clinit> () method, although really exist, but can only be executed by the virtual machine, it will call this method after starting the initiative to use the class initialization, if there are multiple threads access the method, it will not cause thread-safety issues it?

public class ClassInit {
    static{
        try {
            System.out.println ("初始化");
            TimeUnit.SECONDS.sleep (5);
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }

    public static void main(String[] args) {
        IntStream.range (0,5).forEach (value->new Thread (ClassInit::new).start ());
    }
}

Run the above code you will find that only one thread at the same time to perform static code block content, and static code block will only be executed once, JVM ensures <clinit> () synchronization semantics in a multithreaded environment.

Yes, and review the remaining issues above? During the coupling stage the preparation process, impart variable for each class corresponding to the initial value (stored in the process memory area) x = 0 y = 0 singleton = null; skip connected parsing process, look initialization phase, noted here that, call this class of such main trigger initialization operation, and then for each class given the correct value of the variable x = 0 y = 0 singleton = new Singleton (), then the new Singleton () triggers a configuration, leading to increment, this is actually the second time initialization, and then call the main function has class. static method. The third initialization. So three initialization means three calls a clinit way to do that? If the output is 3, but the output is only 1,1 illustrate this class is initialized once. However, still on top, execute the preparation phase given a default value for each of the initial value, the initialization phase, since the sequential clinit, first into the self-energizing construction method, and then initializing the assignment to x, then y is not given, since the initial value, in the constructor value obtained is called with the correct value (the clinit a block of code to assign the class variable), so the result becomes 0, and

Guess you like

Origin blog.csdn.net/qq_40826106/article/details/86511608