2012-11-04 32 views
-1

這是Java語言編寫的代碼:多態棘手的情況

class A{ 
    A() { print(); } 
    void print() { System.out.println("A"); } 
} 
class B extends A{ 
    int i = Math.round(3.5f); 
    public static void main(String[] args){ 
     A a = new B(); 
     a.print(); 
    } 
    void print() { System.out.println(i); } 
} 

它打印0,4。 但是爲什麼從構造函數的超類A中調用子類的打印方法呢?我發現print方法被覆蓋,但實際上'print'方法是從超類中調用的...... 這是爲了準備Java認證而進行的演練。 此致敬禮

+1

是你期待什麼輸出? – fgb

+2

我想輸出可能是A,4 – uml

回答

1

請勿在構造者A中調用print。這是它打印0,因爲B實例顯然是尚未完全初始化,並B.i價值顯然仍是0

隱式構造的B是:

public B() { 
    super(); // invokes B.print! 
    this.i = Math.round(3.5f); 
} 

正如你所看到的,之前i初始化打印被執行。然而,你已經覆蓋print,永遠不會執行舊打印。

0

當您在對象上調用方法時,即使它是從超類內調用的,它始終使用對象實際類型的實現。

1

對象類型(未引用類型)確定哪一個被覆蓋的方法在運行時使用/

A a = new B(); 
a.print();// this would always call B's print() in case of overriden methods 
1

一件事是,用於訪問一個對象和另一個事物的實際類型的對象的引用。這是基本的subtype polymorphism

您的對象是B類型的,因爲這是您創建的(即新B())。現在,您碰巧通過類型A的引用訪問您的對象,這可能是因爲B A(B擴展A)。

當您通過引用調用方法print時,運行時類型系統知道即使引用是A類型,引用指向的實際對象也是類型B,因此它會查找方法先在B中打印。那就是那個被調用的人,這就解釋了你看到的輸出。

您的打印方法是他們所說的virtual method。這意味着它是一個運行時系統,它僅根據運行時調用的目標對象的性質確定將調用該方法的所有實現的哪個實現。

現在,明確地說明,您在B中的重寫實現就是所謂的。 重寫實現不會自動觸發父類中的implmentation。這與構造函數中的行爲有些不同(不能被繼承,但可以被鏈接)。

所以,這基本上意味着,如果從你的覆蓋方法要訪問你必須要問你的超類做到這一點(即super.print())

這樣的父母的行爲,如果您在下列情況下進行處理的構造,就像

class A { 
    public A() { System.out.println("A"); } 
} 

class B extends A{ 
    public B() { System.out.println("B"); } 
} 

如果創建B的情況下,你應該看到一個B.Because構造函數會被自動鏈接的輸出,並在B中的構造函數調用構造函數A.

但是在ca虛擬方法本身,你需要明確鏈執行(如果這就是你想要的)是這樣的:

class A { 
    public A() { System.out.println("A"); } 
    //virtual method 
    public void print(){ System.out.println("A"); } 
} 

class B extends { 
    public B() { System.out.println("B"); } 
    //virtual method overriden 
    @Override 
    public void print(){ 
     super.print(); //invokes A.print 
     System.out.println("B"); 
    } 
} 

...爲了看到輸出的B.