三个例子彻底搞懂Java类属性,代码块,构造方法的执行顺序

三个例子彻底搞懂Java类属性,代码块,构造方法的执行顺序

对于标题所述的加载顺序,可能有些同学和我一样知道静态属性和代码块先加载,非静态属性和代码块其次加载,最后才是构造方法加载。但并没有深入的去了解它。那么我们带着两个问题去看待这个加载顺序。

  1. 是否有可能非静态代码块先于静态方法加载?
  2. 如果子类继承了父类,那么其加载顺序又是怎样的呢?

对于第一个问题我们直接上一个例子。

  public class StaticTest {
    public static int temp = 2;
    public static StaticTest instance = new StaticTest();

    static {
        System.out.println("static StaticTest");
    }

    {
        System.out.println("unStatic StaticTest");
    }

    public StaticTest() {
        System.out.println("constract StaticTest");
        method();
    }

    public void method() {
        System.out.println("method StaticTest");
    }

    @Override
    public String toString() {
        return "toString StaticTest";
    }

    public static void main(String[] args) {
        new StaticTest();
        System.out.println("----------------");
        new StaticTest();
    }

}


打印结果如下

unStatic StaticTest
constract StaticTest
method StaticTest
static StaticTest
unStatic StaticTest
constract StaticTest
method StaticTest
----------------
unStatic StaticTest
constract StaticTest
method StaticTest

可以看到当一个类的静态属性需要自身的构造方法去实现的时候,可以出现非静态代码块先于构造方法和静态方法执行。

针对第二个问题我们上第二个例子

class ParentTest {
    public static String PARENT_STATIC_FIELD = "父类-静态属性";

    // 父类-静态块
    static {
        System.out.println(PARENT_STATIC_FIELD);
        System.out.println("父类-静态代码块");
    }

    public  String parentField = "父类-非静态属性";

    // 父类-非静态块
    {
        System.out.println(parentField);
        System.out.println("父类-非静态代码块");
    }

    public ParentTest() {
        System.out.println("父类—无参构造函数");
    }

}

public class InitOderTest extends ParentTest {
    public static String STATIC_FIELD = "静态属性";

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

    public String field = "非静态属性";

    // 非静态块
    {
        System.out.println(field);
        System.out.println("非静态代码块");
    }

    public InitOderTest() {
        System.out.println("无参构造函数");
    }

    public static void main(String[] args) {
        InitOderTest test = new InitOderTest();
    }
}

打印结果如下:

父类-静态属性
父类-静态代码块
静态属性
静态代码块
父类-非静态属性
父类-非静态代码块
父类—无参构造函数
非静态属性
非静态代码块
无参构造函数

可以得出结论有继承关系的类相关的加载顺序如下:

  1. 父类的静态代码块和属性
  2. 子类的静态代码块和属性
  3. 父类的非静态代码块和属性
  4. 父类的构造方法
  5. 子类的非静态代码块和属性
  6. 子类的构造方法

最后我们来一个实战的列子 代码如下:

public class TestClassLoader {
    static class Father {
        public static final String TAG = "Father";

        static {
            System.out.println("static Father");
        }

        {
            System.out.println("unStatic Father");
        }

        public Father() {
            System.out.println("constract Father");
            method();
        }

        public void method() {
            System.out.println("method Father");
        }

        @Override
        public String toString() {
            return "toString Father";
        }
    }

    static class Son extends Father {
        public static Son instance = new Son();

        static {
            System.out.println("static Son");
        }

        {
            System.out.println("unStatic Son");
        }

        public Son() {
            System.out.println("constract Son");
            method();
        }

        public void method() {
            System.out.println("method Son");
        }

        @Override
        public String toString() {
            return "toString Son";
        }
    }

    public static void main(String[] args) {
        System.out.println("1.---------------------");
        System.out.println(Son.TAG);
        Son[] sons = new Son[10];
        System.out.println(sons);
        System.out.println("2.---------------------");
        System.out.println(Son.instance);
        System.out.println("3.---------------------");
        Son son = new Son();
        Father father = son;
        father.method();
        System.out.println(son);
    }
}

打印结果如下:

1.---------------------
Father
[LTestClassLoader$Son;@61bbe9ba
2.---------------------
static Father
unStatic Father
constract Father
method Son
unStatic Son
constract Son
method Son
static Son
toString Son
3.---------------------
unStatic Father
constract Father
method Son
unStatic Son
constract Son
method Son
method Son
toString Son

综上所述值得我们注意的是,静态属性和代码块只会在类的加载过程中执行一次,而在执行构造方法之前必然要先执行非静态代码块和属性。

你可能感兴趣的:(三个例子彻底搞懂Java类属性,代码块,构造方法的执行顺序)