所以我有以下3个班级:
A" A"使用1个字段和1个调用方法的构造函数:
public class A {
String bar = "A.bar";
A() {
foo();
}
public void foo() {
System.out.println("A.foo(): bar = " + bar);
}
}
第二课" B"继承自A的1个字段和1个调用方法的构造函数:
public class B extends A {
String bar = "B.bar";
B() {
foo();
}
public void foo() {
System.out.println("B.foo(): bar = " + bar);
}
}
第三课" C"包含主要方法:
public class C {
public static void main(String[] args) {
A a = new B();
System.out.println("a.bar = " + a.bar);
a.foo();
}
}
输出是:
B.foo():bar = null
B.foo():bar = B.bar
a.bar = A.bar
我在调试模式下跟踪了程序,我仍然无法弄清楚输出。我将非常感谢对所发生的过程及其背后的原则的详细解释。 非常感谢。
编辑:就像人们指出我确实忘记了输出的最后一行:
B.foo():bar = B.bar
答案 0 :(得分:5)
首先调用B类的构造函数。但是,如果扩展一个类而不显式调用基类的构造函数(或派生类的其他构造函数),那么每个默认构造函数的第一行都是super()
的(隐藏)调用,即构造函数基类(在本例中为A)。因此,我们继续使用A的构造函数,它调用方法foo()
。由于此方法在B类中被覆盖,因此会调用overriden实现。现在事情变得有趣了 - B的构造函数仍然没有完成,所以bar
的值仍未设置,因此输出:
B.foo(): bar = null
我们现在回到B&#39的构造函数中,它输出
B.foo(): bar = B.bar
最后,输出
a.bar = A.bar
答案 1 :(得分:2)
B.foo(): bar = null
'因为对象尚未初始化B.foo(): bar = B.bar
以下是此
的文档子类属性仅隐藏超类attrs。 https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
关于超级作品和超级构造者的一些注释 https://docs.oracle.com/javase/tutorial/java/IandI/super.html
不要在构造函数中调用可覆盖的方法 https://www.securecoding.cert.org/confluence/display/java/MET05-J.+Ensure+that+constructors+do+not+call+overridable+methods
P.S。你错过了你提供给我们的输出中的最后一个方法调用
答案 2 :(得分:1)
在超构造函数调用和this-constructor主体之间插入初始化代码。因此B的构造函数非常像
B()
{
super(); // A()
this.bar = "B.bar";
foo();
}