对于以下代码,结果为
I am in B, value is 0
I am in B, value is 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);
}
}
}
首先,为什么构造函数会被调用两次?
为什么b.a
的值为22
?
最后,为什么第一个a
的值为0
?
最佳答案
只要您不提供对父类(super class)构造函数的显式调用,Java 编译器就会为您插入对默认父类(super class)构造函数的隐式调用(无参数)。就好像您的 B
构造函数实际上是:
public B() {
super();
a = 44;
diplay();
}
对父类(super class)构造函数的调用会调用 P
构造函数,后者又调用 diplay
。该对象实际上是一个 B
,因此通过多态性,将调用 B
的 diplay
方法。
此时,您已经泄漏了您的子类实例,因为它尚未完全构造。因此,B
的变量a
,隐藏了P
的变量a
,还没有被初始化,所以它仍然有默认值,0
.
然后,父类(super class) P
构造函数完成,B
构造函数的其余部分运行,同时也会调用 diplay
。此调用会看到初始化的 44
值。
构造函数不会被调用两次;子类构造函数 B
隐式调用父类(super class)构造函数 P
,并且两个构造函数都调用 diplay
。
回到main
,您引用了字段a
,但引用是在P
类型的变量上。没有字段多态性,因此即使运行时对象是 B
,也会检索到 P
的 a
值,即初始化为22
。
此代码说明了为什么通常不是一个好主意
- 在构造函数完成之前泄漏
this
对象实例,并且 - 有意在子类中声明与父类(super class)中同名的变量。
关于java - 扩展类构造函数被调用两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51073396/