The initialization order of Java classes (the execution order of static variables, ordinary member variables, static code blocks, and construction methods); the execution timing of static static code blocks

Parent class static member variable -> This class static variable -> Parent class non-static variable -> Parent class constructor -> This class non-static variable -> This class constructor

public class Main {
    
    
 
    public static void main(String[] args) {
    
    
        TestClass tc = new TestClass();
    }
 
    private static class Base {
    
    
        public Base(String id) {
    
    
            System.out.println("Base initialized :"+id);
        }
    }
    private static class Parent {
    
    
        Base b2 = new Base("b2");
        static Base b4 = new Base("b4");
        public Parent() {
    
    
            System.out.println("Parent initialized.");
            testSync();
        }
        public void testSync() {
    
    
            System.out.println("Parent testSync.");
        }
    }
    //测试java 构造函数和类变量的初始化流程:
    //static成员变量会最先被初始化
    //然后是父类构造函数
    //然后是非static成员变量
    //然后是本类构造函数
    private static class TestClass extends Parent{
    
    
        private final static Base b = new Base("b1");
        private final Base b3 = new Base("b3");
        public TestClass() {
    
    
            //super();
            synchronized(b3) {
    
    
                System.out.println("TestClass initialized.");
            }
        }
        @Override
        public void testSync() {
    
    
            synchronized(b) {
    
     //crash on synchronized(b3)
                System.out.println("TestClass testSync.");
            }
        }
    }
}



The initialization order of Java classes (the execution order of static variables, ordinary member variables, static code blocks, and construction methods); the execution timing of static static code blocks

1. Classification of code blocks

Basically, there are three types of code blocks: static static code blocks, structural code blocks, and ordinary code blocks

Code block execution order Static code block --> Construct code block --> Constructor function --> Ordinary code block

Execution order of code blocks in inheritance: parent class static block --> child class static block --> parent class code block --> parent class constructor --> child class code block --> child class constructor

1.1 Static code block (also called static block, static initialization block)

The code in the Java static code block will run when the class loads the JVM, and will only be executed once, which means that these codes can be called without instantiating the class. In general, if some code must be executed when the project starts, you need to use static code blocks, so static blocks are often used to initialize class properties!

Five small points about Static static code blocks

1. The code in the Java static code block will run when the class loads the JVM, and it will only be executed once. 2. The
static block is often used to perform the initialization of class attributes.
3. The static block takes precedence over various code blocks and constructors. If a class There are multiple static code blocks in , which will be executed in order of writing
4. Static code blocks can be defined anywhere in the class except in the method body [the method body here is any method body]
5. Static code blocks cannot access ordinary variables

The reason described in 4 that the static code block cannot exist in any method body is actually very simple, because the ordinary method loads the class, and then instantiates the object with new, and the method can be run through the object, while the static code block only needs to load the class After that it will work. For static methods, when the class is loaded, the static method has also been loaded, but we must access it through the class name or object name, that is to say, compared with static code blocks, static code blocks are actively run by themselves, and Static methods are invoked passively. Regardless of the method, we need to make it clear that the existence of static code blocks will automatically run when the class is loaded, and it cannot be run automatically when placed in a normal method or a static method.

1.2 Constructing code blocks (also called constructing initialization blocks)

Listening to the name, you know that it is inseparable from the construction method! That's right, but it is still fundamentally different from the construction method. We all know that there can be many construction methods in each method. Every time an object is created, one construction method is executed, and a construction method can create N objects. The construction method It is more "cold", but the construction code block is more "dog-licking". As long as an object of this class is instantiated, the construction code will be executed once, and the construction code block will be called in advance every time an object is created. So it can count the number of times objects are created. Of course, relatively little is used to construct code blocks!

Construct a code block summary:

1. The construction code block is called when the object is created, and it will be called once every time the object is created.
2. The construction code block is executed prior to the constructor, and the operation of the construction code block depends on the constructor
. 3. The construction code block is defined in the class

For the "dependency" in 2, it can be understood that if the object is not instantiated (that is, the construction method is not executed), the construction code block will not be executed!

1.3 Code block (also known as common code block, initialization block)

code block summary

1. Ordinary code blocks are defined in the method body
2. The format of ordinary code blocks and construction code blocks is {}
3. The only difference between ordinary code blocks and construction code blocks is that construction code blocks are in classes defined, while normal code blocks are defined in the method body

1.4 Code Testing

package com.ttbank.flep.test;

public class Initializationblock {
    
    
    int intA;
    int intB;


    public Initializationblock() {
    
    
        System.out.println("无参构造器00000000");
    }

    public Initializationblock(int a) {
    
    
        System.out.println("一个参数的构造器");

    }


    {
    
    
        intA = 10;
        intB = 15;

        System.out.println("构造初始化块11111");
    }

    {
    
    
        System.out.println("构造初始化块22222");
    }

    {
    
    

        System.out.println("构造初始化块33333");
    }

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

    static {
    
    
        System.out.println("静态初始化块0202020202");
    }
    public void method(){
    
    
        {
    
    
            System.out.println("普通初始化块");
        }
    }
}

test demo

package com.ttbank.flep.test;

public class Test3 {
    
    


    /**
     * @param args
          * 因为静态块是在类的初始化阶段完成的,
          * 因此在创建某个类的第二个对象时,该类的静态块就不会执行了
         *
          * 在单个类中,静态初始化块,初始化块,构造器
          * 多个类的继承中初始化块、静态初始化块、构造器的执行顺序
         在继承中,先后执行父类A的静态块,父类B的静态块,最后子类的静态块,然后再执行父类A的非静态块和构造器,然后是B类的非静态块和构造器,最后执行子类的非静态块和构造器
     */
    public static void main(String[] args) {
    
    
        Initializationblock initializationblock = new Initializationblock();
        initializationblock.method();
        System.out.println("------------");
        //多打印几个对象的目的是:好看出Static静态代码块只执行一次!!!
        Initializationblock initializationblock2 = new Initializationblock(); //因为静态块是在类的初始化阶段完成的,因此在创建某个类的第二个对象时,该类的静态块就不会执行了
        initializationblock2.method();
        Initializationblock initializationblock3 = new Initializationblock();
        initializationblock3.method();
    }
}

print result

静态初始化块01010101
静态初始化块0202020202
构造初始化块11111
构造初始化块22222
构造初始化块33333
无参构造器00000000
普通初始化块
------------
构造初始化块11111
构造初始化块22222
构造初始化块33333
无参构造器00000000
普通初始化块
构造初始化块11111
构造初始化块22222
构造初始化块33333
无参构造器00000000
普通初始化块

Draw conclusions: Execution order static code block > construction code block > constructor > normal code block

2. Static static code block execution timing

The real execution time of the static block. If we understand the principle of JVM, we know that the operation of a class is divided into the following steps:

(1) load
(2) connect
(3) initialize

2.1 Loading phase

The loading phase consists of three basic actions:

(1) Through the fully qualified name of the type, generate a binary data stream representing the type
(2) parse the binary data stream for the internal data structure in the method area
(3) construct a java.lang.Class representing the type Instances of classes
In addition, if a class loader encounters missing or wrong class files during preloading, it needs to wait until the program actively uses the class for the first time before reporting the error.

2.2 Connection phase

The connection phase is further divided into three parts:

(1) Verification, confirm that the type conforms to the semantics of the Java language, check the binary compatibility between each class (for example, final classes do not need to have subclasses, etc.), and also need to verify symbol references.
(2) Preparation, the Java virtual machine allocates memory for class variables, and sets the default initial value.
(3) Parsing (optional), looking for symbolic references of classes, interfaces, fields and methods in the type constant pool, and replacing these symbolic references with direct references.

2.3 Initialization phase

When a class is actively used, Java Virtual will initialize it. The following six situations are actively used:

(1) When creating a new instance of a certain class (such as through new or reflection, cloning, deserialization, etc.) (
2) When calling a static method of a certain class
(3) When using a static method of a certain class or interface Field
(4) When calling certain reflection methods in the Java API, such as methods in the class Class, or methods in classes in java.lang.reflect (
5) When initializing a subclass
(6) When virtual The machine starts a class marked as the startup class (that is, the class containing the main method). The
Java compiler will collect all class variable initialization statements and static initializers of the type, and put these into a special method: clinit.

2.4 Summary

In fact, the execution of static blocks occurs during the "initialization" phase. In the initialization phase, jvm mainly completes the initialization of static variables and the execution of static blocks.

Let's look at several situations in which static blocks are executed:

1. The process of new A() will print "" for the first time; because this process includes initialization

2. The first Class.forName("A") process will print ""; because this process is equivalent to Class.forName("A",true,this.getClass().getClassLoader());

3. For the first time, the process of Class.forName("A", false, this.getClass().getClassLoader()) will not print "". Because false indicates that the process of loading the class is not initialized. If it is not initialized, the static block will not be executed.

3. The initialization order of a single class

For static variables, static initialization blocks, variables, initialization blocks, and constructors, their initialization sequence is (static variables, static initialization blocks)>(variables, initialization blocks)>constructors.

Graphic:

img

Verify this with the following test code:

package com.ttbank.flep.file.test;

public class TradeTest {
    
    
    // 静态变量
    public static String staticField = "静态变量";

    // 变量
    public String field = "变量";

    // 静态初始化块
    static {
    
    
        System.out.println(staticField); //注意:静态初始化块中使用静态变量,所以静态变量要在静态代码块前
        System.out.println("静态初始化块");
    }

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

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

    public static void main(String[] args) {
    
    
        new TradeTest();
        new TradeTest();
    }

}

Execution effect diagram:

img

Static code blocks are loaded and executed when the virtual machine loads a class, and only executed once ;
non-static code blocks are executed when an object is created (that is, when an object is new), and executed once each time an object is created.

4. For the case of inheritance, the initialization order

img

father:

package com.ttbank.flep.file.test;

public class Father {
    
    
    // 静态变量
    public static String f_StaticField = "父类--静态变量";
    protected int i = 1;
    protected int j = 8;
    // 变量
    public String f_Field = "父类--变量";

    // 静态初始化块
    static {
    
    
        System.out.println(f_StaticField);
        System.out.println("父类--静态初始化块");
    }

    // 初始化块
    {
    
    
        System.out.println(f_Field);
        System.out.println("父类--初始化块");
    }

    // 构造方法
    public Father() {
    
    
        System.out.println("父类--构造器");
        System.out.println("i=" + i + ", j=" + j);
        j = 9;
    }


}

Subclass:

package com.ttbank.flep.file.test;

public class Son extends Father {
    
    
    // 静态变量
    public static String s_StaticField = "子类--静态变量";

    // 变量
    public String s_Field = "子类--变量";

    // 静态初始化块
    static {
    
    
        System.out.println(s_StaticField);
        System.out.println("子类--静态初始化块");
    }
    // 初始化块
    {
    
    
        System.out.println(s_Field);
        System.out.println("子类--初始化块");
    }

    // 构造器
    public Son() {
    
    
        System.out.println("子类--构造器");
        System.out.println("i=" + i + ",j=" + j);
    }

    // 程序入口
    public static void main(String[] args) {
    
    
        new Son();
    }
}

Results of the:

img

Conclusion: The approximate order of execution is as follows,

(1) In a class that does not exist inheritance: initialize static variables, execute static initialization block -> initialize ordinary member variables (if there is an assignment statement), execute ordinary initialization block -> construction method

(2) In a class with inheritance: initialize the parent class static member variable, run the parent class static initialization block –> initialize the subclass static member variable, run the subclass static initialization block –> initialize the parent class instance member variable (if any Assignment statement), execute parent class ordinary initialization block –> parent class construction method –> initialize subclass instance member variables (if there is an assignment statement) and ordinary initialization block –> subclass construction method.

References: https://blog.csdn.net/xyajia/article/details/80922329、

https://blog.csdn.net/qq_44543508/article/details/102593419—recommended

https://blog.csdn.net/berber78/article/details/46472789—Recommended

Guess you like

Origin blog.csdn.net/qq_43842093/article/details/130118949