静态代码块、静态变量、成员变量等加载顺序详解

静态代码块、静态变量、成员变量等加载顺序详解

1 单个类的初始化顺序

一个类 无论创建多少对象,静态数据只占用一份存储区域,且只在类第一次初始化的时候进行静态数据初始化

顺序如下:

单个类而言: 静态变量/静态代码块 --> 成员变量(普通代码块) --> 构造方法 --> 静态方法

构造方法本身也是静态方法

栗子

public class TestStatic {
    {
        System.out.println("代码块1");
    }
    /*静态代码块*/
    static {
        System.out.println("静态代码块");
    }
    static Test test = new Test();

    String s = "成员变量";

    TestStatic (){
        System.out.println(s + "TestStatic 构造方法");
    }
    {
        System.out.println("代码块2");
    }

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

class Test {
    Test(){
        System.out.println("test构造方法");
    }
}
/*结果如下
静态代码块
test构造方法
代码块1
代码块2
成员变量TestStatic 构造方法

Process finished with exit code 0
说明 在加载main 方法之前 需要先加载这个类 
所以在不实例化这个对象之前的结果是
静态代码块
test构造方法

Process finished with exit code 0
加载顺序: 加载类 --> 静态变量、静态代码块(先后顺序加载) --> 成员变量、一般代码块 --> 构造方法

加载顺序: 加载类 --> 静态变量、静态代码块(先后顺序加载) --> 成员变量、普通代码块 --> 构造方法

再来个栗子

class Bowl {
    Bowl(int marker) {
        System.out.println("Bowl(" + marker + ")");
    }

    void f1(int marker) {
        System.out.println("f1(" + marker + ")");
    }
}

class Table {
    static Bowl bowl1 = new Bowl(1);
    Table() {
        System.out.println("Table()");
        bowl2.f1(1);
    }
    void f2(int marker){
        System.out.println("f2(" + marker + ")");
    }
    static Bowl bowl2 = new Bowl(2);
}

class Cupboard {
    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);
    Cupboard (){
        System.out.println("Cupboard()");
        bowl4.f1(2);
    }
    void f3(int marker){
        System.out.println("f3(" + marker +  ")");
    }
    static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {

    public static void main(String[] args) {
        System.out.println("Creating new Cupboard() in main");
        new Cupboard();
        System.out.println("Creating new Cupboard() in main");
        new Cupboard();
        table.f2(1);
        cupboard.f3(2);
    }
    static Table table = new Table();
    static Cupboard cupboard = new Cupboard();
}

/**
结果如下: 
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(2)

Process finished with exit code 0
**/

父子类初始化顺序

多个类 其实也差不多,顺序如下:

父类静态变量、静态代码块 --> 子类静态变量、静态代码块 --> 父类成员变量、普通代码块--> 父类构造方法 --> 子类成员变量、普通代码块--> 子类构造方法

栗子来了

/*子类*/
public class Child extends Parent {

    static {
        System.out.println("子类静态代码块");
    }
    static TestChild test = new TestChild();

    {
        System.out.println("子类代码块1");
    }

    String s = "子类成员变量";

    {
        System.out.println("子类代码块2");
    }

    Child() {
        System.out.println("子类构造器" + s);
    }

    public static void main(String[] args) {
        Parent c = new Child();
    }

}
    class TestChild {
        TestChild (){
        System.out.println("用于测试子类静态变量顺序");
    }
}


/*父类*/
package com.windy.testBook.five;

/**
 * @Author windy
 * @Desp
 * @Date 2019-03-23 17:13
 */
public class Parent {

    static TestParent test = new TestParent();

    static {
        System.out.println("父类静态代码块");
    }
    Parent () {
        System.out.println("父类构造器" + s);
    }

    {
        System.out.println("父类代码块1");
    }

    String s = "父类成员变量";

    {
        System.out.println("父类代码块2");
    }
}
    class TestParent {
    TestParent (){
        System.out.println("用于测试父类静态变量顺序");
    }
}

/*结果
用于测试父类静态变量顺序
父类静态代码块
子类静态代码块
用于测试子类静态变量顺序
父类代码块1
父类代码块2
父类构造器父类成员变量
子类代码块1
子类代码块2
子类构造器子类成员变量

Process finished with exit code 0
*/

静态代码块或者静态变量是对象加载的时候进行的 只加载一次。如上面所有 只有一个存储区域。而成员变量或者普通代码块 每次实例的时候 都会执行一次 而且都优先于构造方法

你可能感兴趣的:(静态代码块、静态变量、成员变量等加载顺序详解)