扩展类的constuctor被调用两次

chr*_*ina 2 java constructor

对于以下代码,结果是

我在B,值是0
我在B,值是44
22

public class Test {
    public static void main(String[] args) {
        P b = new B();
        System.out.println(b.a);
    }

    static class P {
        public int a = 11;

        public P() {
            a = 22;
            diplay();
        }

        public void diplay() {
            System.out.println("I am in P, value is " + a);
        }
    }

    static class B extends P {
        int a = 33;

        public B() {
            a = 44;
            diplay();
        }

        public void diplay() {
            System.out.println("I am in B, value is " + a);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

首先,为什么构造函数被调用两次?
为什么b.a价值22
最后,为什么第一个a价值0呢?

rge*_*man 7

每当您不提供对超类构造函数的显式调用时,Java编译器会为您插入对默认超类构造函数的隐式调用(无参数).这就像你的B构造函数真的:

public B() {
    super();
    a = 44;
    diplay();
}
Run Code Online (Sandbox Code Playgroud)

对超类构造函数的调用调用P构造函数,该构造函数调用diplay.对象是真的B,所以用多态性,Bdiplay方法被调用.

此时,您已泄露了子类实例,因为它尚未完全构建. 正因为如此,B的变量a,隐藏P的变量a,尚未初始化还,所以它还是有它的默认值,0.

然后超类P构造函数完成,构造函数的其余部分B运行,也调用diplay.此调用将查看初始化44值.

构造函数不会被调用两次; 子类构造函数B隐式调用超类构造函数P,两个构造函数都调用diplay.

返回main,您引用该字段a,但引用是在类型的变量上P.没有字段多态,因此即使对象是B在运行时,也会检索P's 的值a,并将其初始化为22.

这段代码说明了为什么它通常不是一个好主意

  1. this在构造函数完成之前泄漏对象实例,和
  2. 故意在子类中声明变量,其名称与超类中的名称相同.