转: https://www.zhihu.com/question/41924954
下面代码的输出是什么?
实际结果是:
I am in B, value is 0
I am in B, value is 44
22
对这一结果我没有任何思路,不知道为什么,尤其是0.
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); } } }
解释1:
例子里,P.display()与B.display()构成覆写(override)关系:后者覆写前者。这是虚方法的多态性的表现。
所以在创建B类实例时,虽然会(显式或隐式)调用到P的构造器,但在P的构造器里调用的display()方法永远是按照虚方法的查找规则,找到该实例最准确的实现,所以P()里调用display()找到的是B.display()方法。
而字段永远不参与多态,哪个类的方法访问某个名字的字段时,该名字指的就是该类能看到的那个字段。当子类声明了与父类同名的字段时,虽然在子类里两个字段都会存在,但是子类的字段会遮蔽了父类的同名字段。
此例中,P.display()里访问“a”访问的是P.a,而B.display()里访问“a”访问的是B.a。
解释2:
首先,你的這個程序「翻譯」過來,是這樣的:(每個 a 的賦值實際都是在 constructor 裏執行的)
註釋裏的數字,是每一行發生的順序。
可以看到當09發生的時候,輸出的是 B 自己的 a,而這個 a 是一個成員變量,同時沒有被賦任何值,所以是 int 成員變量的 default value,即0。
public class Test {
public static void main( String [] args ) {
P b = new B(); // 01
System.out.println( b.a ); // 15
}
static class P {
public int a;
public P() { // 04
a = 11; // 05
a = 22; // 06
diplay(); // 07
}
public void diplay() {
System.out.println( "I am in P, value is " + a );
}
}
static class B extends P {
int a;
public B() { // 02
super(); // 03
a = 33; // 10
a = 44; // 11
diplay(); // 12
}
public void diplay() { // 08, 13
System.out.println( "I am in B, value is " + a ); // 09, 14
}
}
}
可以看到當09發生的時候,輸出的是 B 自己的 a,而這個 a 是一個成員變量,同時沒有被賦任何值,所以是 int 成員變量的 default value,即0。