类加载器

类加载器

以下是一道AK的笔试题,可以很好的理解类加载顺序:

public class ParentTest {
    static {
        System.out.println("parent1");
    }

    {
        System.out.println("parent2");
    }

    ParentTest() {
        System.out.println("parent3");
    }

    public static void main(String[] args) {
        ChildTest obj = new ChildTest();
    }
}

class ChildTest extends ParentTest {
    static {
        System.out.println("child1");
    }

    {
        System.out.println("child2");
    }

    ChildTest() {
        System.out.println("child3");
    }
}

类加载时就执行静态初始化块,如果有父类的话,先加载父类(只执行父类的静态代码块,其他非静态代码块、静态方法以及非静态方法不执行)。加载完成后,调用构造器的话,会先执行非静态初始化块,再执行构造方法。当然,如果有父类,则先执行父类的非静态初始化块和构造方法,再执行子类的非静态代码块和构造方法。如果不调用构造器,而是直接调用静态方法的话,则非静态初始化块及父类的非静态初始化块不会执行,构造方法和父类的构造方法也不会执行。每个类的静态初始化块都只会被执行一次,在类加载的时候执行。而非静态初始化块可能会执行多次,每调用一次构造器或者子类的构造器,都会执行一次。

所有,上面打印的结果是:

parent1

child1

parent2

parent3

child2

child3

再来一个强化一下:

public class ClassB extends ClassA {

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

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

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

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

    public ClassB() {
        System.out.println("子类构造函数");
    }

    public static void main(String[] args) {
        System.out.println("....主方法开始....");
        new ClassB();
        System.out.println("************");
        new ClassB();
        System.out.println("....主方法结束....");
    }

}

class ClassA {

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

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

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

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

    public ClassA() {
        System.out.println("父类构造函数");
    }

}

打印什么?这里不再写出来,每次复习的时候直接做这个题目,再跟答案对比,在看文中解释,对理解记忆有帮助。

原文地址:https://www.cnblogs.com/koushr/p/9520811.html