2013-11-02 114 views
3

最近我偶然發現了Java測試,發現了一個奇怪的行爲。Java繼承基類使用派生類方法

class MainOne { 

    private int i = 5; 

    public MainOne() { 
     System.out.println("MainOne says that I is " + getI()); 
    } 

    public int getI() { 
     System.out.println("MainOne getI was used"); 
     return i; 
    } 

} 

public class TheTest extends MainOne { 

    private static int i = 10; 

    public TheTest() { 
     System.out.println("TheTest says that I is " + super.getI()); 
    } 


    public int getI() { 
     System.out.println("TheTest getI was used"); 
     return i; 
    } 

    public static void main(String[] args) { 
     TheTest test = new TheTest(); 
    } 

} 

結果爲:

TheTest格提使用

銘萬說,我是10.

銘萬格提使用

TheTest說我是5

問題是,發生了什麼事? Base類如何使用它的後代方法?

+0

你是什麼意思?它們在構造函數中被調用。 – Rofgar

回答

5

這是關於執行和構造函數繼承的順序。 TheTest構造函數隱式調用構造函數superMainOne

所以

public TheTest() { 
    System.out.println("TheTest says that I is " + super.getI()); 
} 

調用

public MainOne() { 
    System.out.println("MainOne says that I is " + getI()); 
} 

它調用重寫getI()因爲多態性。

public int getI() { 
    System.out.println("TheTest getI was used"); 
    return i; 
} 

這裏的iTheTest宣佈static i。最後

super.getI()); 

被調用它採用MainOnei

你因此得到

TheTest getI was used 

MainOne says that I is 10. 

MainOne getI was used 

TheTest says that I is 5 

注意多態性不適用於字段和領域(無論是static或實例)可能隱藏在父類中的同名字段。

+0

但是多態是如何起作用的?基類在調用getI()方法時不應該知道它的派生類。 – Rofgar

+0

@Rofgar基類不知道,但JVM確實。這是後期綁定的結果。 –

+0

哦,這很有道理。謝謝。這仍然是一個棘手的情況。 – Rofgar

0

在這個問題中有兩點需要注意。裏面MainOne

public TheTest() { 
    System.out.println("TheTest says that I is " + super.getI()); 
} 

  1. super.getI()調用強制此調用去,即使該方法被重寫超類。在亞類

  2. i字段被定義爲一個場static

    有基於該字段是否是靜態或不結果的差。當從TheTest構造函數調用覆蓋的getI()時,調用將轉到MainOne類方法。但是,當發生此調用時,TheTest類的實例字段尚未初始化爲分配的值(但僅爲默認值)。

    如果TheTest領域i是一個實例字段,getI()將打印調用序列的0而不是10

    細節很難在這裏代表。但如果您想了解更多詳情,請參閱下文。

    new TheTest() 
        -> super() - implicitly invoke default constructor 
         -> inside MainOne() constructor 
          -> System.out.println("MainOne says that I is " + getI()); 
           -> this results in a getI() invocation 
           -> since getI() is overridden by subclass 
           -> invoke on TheTest instance, not MainOne class. 
           -> TheTest's instance fields not given the assigned values 
           -> TheTest's static fields have got the assigned values 
          <- string concatenation completes for System.out.println() 
         <- MainOne constructor (or the super) is completed 
        <- super() completes 
    
        -> System.out.println("TheTest says that I is " + super.getI()); 
         -> this results in a getI() invocation 
         -> however explicit super.getI() forcefully goes to super class 
         -> invoke on MainOne (super) instance, not TheTest class. 
        <- string concatenation completes for System.out.println() 
    <- new TheTest() constructor completes 
    

希望這有助於你進一步瞭解細節。