JVM class loading mechanism (1) [Class loading mechanism and class loading timing]

Preface : We know that a .java file will form one or more corresponding Class files after compilation. These Class files describe various information of the class, and they all need to be loaded into the virtual machine in order to be run and use. In fact, the virtual machine loads the data describing the class from the Class file into the memory, and the data is verified, converted, parsed and initialized, and finally the process of forming a Java type that can be directly used by the virtual machine is the class loading mechanism of the virtual machine. So, when does the jvm load the Class file and initialize the class? How does the jvm load the Class file? What are the steps for jvm to load a Class file? These three problems are the problems that I will focus on solving for jvm class loading. Correspondingly, I will explain them in three blog posts. This article mainly discusses the first problem.

1. What is the class loading mechanism?


The Java virtual machine loads the data describing the class from the Class file into the memory, and verifies, converts, parses and initializes the data, and finally forms a Java type that can be directly used by the virtual machine. This is the loading mechanism of the virtual machine.

      The life cycle of a class: a class starts from being loaded into the virtual machine memory and ends when it is unloaded from the memory. Its entire life cycle includes: Loading, Verification, Preparation, Resolution, Initialization (Initialization), use (using), and unloading (Unloading) seven stages. The three parts of verification, preparation and analysis are collectively referred to as linking. The sequence of occurrence of these seven stages is shown in the following figure:
write picture description here
        As shown in the figure above, the order of the five stages of loading, verification, preparation, initialization and unloading is determined Yes, the class loading process must start step by step in this order, while the parsing phase is not necessarily, it can start after the initialization phase in some cases. It is important to note that the class loading process must be "started" step-by-step in this order, not step-by-step "going" or "finishing", because these stages are usually mixed with each other, that is to say Usually one stage is called or activated while another stage is executing.

When does the JVM load the class?


After understanding the life cycle of a class, let's see when does the jvm load a Class file and initialize the class?

1. Class loading timing:

        The Java virtual machine specification does not stipulate when the class loading phase is required. We will not delve into this. Next, we will focus on the initialization timing of the class.

2. Class initialization timing:

        Class initialization refers to the process of assigning initial values ​​to various class members (member variables modified by static) in the class, which is a stage in the class life cycle.

        Active reference: After a class is actively referenced, the initialization process will be triggered.
        The virtual machine specification states that there are only five situations in which a class must be initialized immediately (this happens after loading, validating, preparing):

        1. When encountering the four bytecode instructions of new, getstatic, putstatic or invokestatic, if the class has not been initialized, you need to trigger its initialization first. The most common Java code scenario to generate these 4 instructions is:

        使用new关键字实例化对象时;
        读取或者设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)时;
        调用一个类的静态方法的时候。

        2. When using the method of the lava.lang.reflect class to make a reflection call to a class, if the class has not been initialized, its initialization needs to be triggered first.

        3. When initializing a class, if you find that its parent class has not been initialized, you need to trigger the initialization of its parent class first.

        4. When the virtual machine starts, the user needs to specify a main class to be executed (the class containing the main() method), and the virtual machine will initialize this main class first.

    5. When using jdk1.7 dynamic language support, if the last parsing result of a java.lang.invoke.MethodHandle instance is the method handle of REF_getstatic, REF_putstatic, REF_invokeStatic, and the class corresponding to this method handle has not been initialized, you need to first to trigger its initialization. [I don't know much about jdk1.7 dynamic language, you can read this article: http://www.infoq.com/cn/articles/jdk-dynamically-typed-language ]

        Passive reference: If a class is passively referenced, the class will not trigger the initialization process.
         1. Referencing the static fields of the parent class through the subclass will not cause the subclass to initialize.
For static fields, only the class that directly defines the field will be initialized, so when we refer to a static field defined in the parent class through a subclass, only the initialization of the parent class will be triggered, but the initialization of the subclass will not be triggered.

public class GrandFatherClass{
    static{
        System.out.println("GrandFatherClass init!");
    }

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

public class FatherClass extends GrandFatherClass{
    static{
        System.out.println("FatherClass init!");
    }

    public static int value = 123;

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

public class SubClass extends FatherClass{
    static{
        System.out.println("SubClass init!");
    }

    static int a;

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

public class Test{
    public static void main(String[] args){
        System.out.println(SubClass.value);
    }
}

/**
    输出:
    GrandFatherClass init!
    FatherClass init!
    123
*/

        In addition, in this example, when initializing the class FatherClass, the virtual machine finds that its parent class GrandFatherClass has not been initialized, so the virtual machine will first initialize the parent class GrandFatherClass, and then initialize the subclass FatherClass, while SubClass will never be initialized.

        2 Referencing a class through an array definition does not trigger initialization of this class.

public class Test{
    public static void main(String[] args){
        SubClass [] sca = new SubClass [10];
    }
}

        The above code produces no output, indicating that the SubClass class is not initialized.

        3. Constants will be stored in the constant pool of the calling class during the compilation phase. Essentially, there is no direct reference to the class that defines the constant, so the initialization of the class that defines the constant will not be triggered.

public class ConstClass{

    static{
        System.out.println("ConstClass init!");
    }

    public static  final String CONSTANT = "hello world";
}

public class Test{
    public static void main(String[] args){
        System.out.println(ConstClass.CONSTANT);
    }
}

/**
    输出:
    hello world
*/

        The above code only outputs "hello world", indicating that the ConstClass class is not initialized.
During the compilation phase, the value of the constant CONSTANT will be stored in the constant pool of ConstClass, so the reference of ConstClass.CONSTANT is converted into the reference of the ConstClass class to its own constant pool.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324871650&siteId=291194637