初始化的棘手顺序

时间:2017-04-11 20:00:59

标签: java initialization

我不是java的新手,但我有一个让我困惑的例子。 这是:

class A {
    public A() { System.out.print("O"); }
}

class B {
    { System.out.print("A"); }
    public B() { System.out.print("D"); }
}

class C {
    static { System.out.print("3"); }
    public C() { System.out.print("P"); }
}

public class D extends C {
    private A objA = new A();
    private static B objB = new B();
    public D() { System.out.print("T"); }

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

那么system.out的结果是什么? 我们知道静态成员是第一个,因此“3”将首先打印,因为它在超类中,private static B objB = new B();将在它之后初始化(实例初始化器,然后是构造函数)。

我们在控制台中获得3AD

然后main方法运行并创建一个D类的新实例,确定。

但是从这一步开始,命令很奇怪:

1 超类public C() { System.out.print("P"); }

的构造函数 控制台中的

3ADP

2 然后D.class私人的字段A objA = new A();

控制台中的

3ADPO

3 D.class的构造函数是最后一个,所以:

控制台中的

3ADPOT

所以问题是:为什么超类构造函数在子类的字段之前运行?我认为构造函数的优先级最低。任何人都可以在docs上分享链接吗?

1 个答案:

答案 0 :(得分:0)

如果我们认为那么很容易理解,首先子类继承自超类,然后只能覆盖行为或访问超类中定义的属性。

每当我们创建一个类A的对象时,首先检查该类是否已加载,如果没有,则加载它,如果它存在则调用其静态initilizer,然后启动所有静态字段(使用默认值或定义的值)。调用此超级构造函数后,将设置由超类设置的所有属性。然后启动所有实例字段,最后执行A的构造函数代码。

以下是执行顺序。

public class A{
    static{ 
       // 1
    }
    int x = 30; // 3
    public  A(){
       //4
    }
}

public class B extends A{
    static{
        //2
    }
    private int s = 60; //5
    public B(){
         //6
    }
}

public class Test {
    public static void main(String[] args){
       new B();
    }
}