转: 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。

由于题主给的例子里两次display()调用都调用到了B.display(),显示的值自然就是B.a的值。一切就都解决了。 
 
解释2:
首先,你的這個程序「翻譯」過來,是這樣的:(每個 a 的賦值實際都是在 constructor 裏執行的)
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。
posted on 2021-03-10 17:40  swing07  阅读(45)  评论(0编辑  收藏  举报