2017-07-01 131 views
1

我包括代碼的輸出是很醜陋,但它只是一個代碼,瞭解不同的事情怎麼可以在Java中工作。被質疑的行標有代碼下半部分的評論。引用類型

class CsTorta extends Torta{ 

public CsTorta retegez(CsTorta a){ 
    .... 
} 
public CsTorta retegez(Torta a){ 
    System.out.println("This method");    //<-----it calls this one and not the one above 
    .... 
} 

} 

public class NewClass { 
public static void main(String[] args) { 
    Torta tt=new Torta(5); 
    Torta tcs=new CsTorta(3); 
    CsTorta cs=new CsTorta(4); 
    System.out.println(""); 
    System.out.println(tcs.retegez(tcs)); //The line in question uses the cstorta retegez method (marked with "This method") 

} 

} 

雖然TCS在編碼時類型是參考的類型,在運行時,當我把它識別出其一個cstorta類型tcs.retegez方法,但是這是相同的TCS參數保持引用類型(那就是爲什麼它使用cstorta標記的方法)。

我的問題是:我的結論是否正確:如果程序調用方法,程序只檢查「真實」類型的對象,如果不是,則使用引用類型?

+0

好吧,我做到了。 –

+0

正確的擴展對象在Java中有點棘手,並可能導致延遲的運行時異常。 –

+2

是的,Java僱傭了[Single-dispatch](https://www.wikiwand.com/en/Dynamic_dispatch#/Single_and_multiple_dispatch) –

回答

1

這是非常正確的。這裏需要的是理解超載覆蓋之間的差異。

當您有一個聲明實例方法的類和一個聲明相同方法(相同名稱,相同參數 - 結果類型通常相同但可能是子類)的子類時,會覆蓋覆蓋率。有多種方法可供選擇,但確切的方法是在運行時確定的。

public class A { 
    public void method1(String s1, int s2) { ... } 
} 

public class B extends A { 
    @Override 
    public void method1(String s1, int s2) { ... } 
} 

A object = new B(); 
object.method1("xxx",2); 

有關運行哪個method1的決定不會在運行時間之前完成。 object的真正類型是B,所以在B宣佈method1被調用。

重載是當兩個方法具有相同的名稱,但不同的參數,都存在。通過不同的參數,我的意思是參數的數量是不同的,或者參數的數量是相同的,但是類型是不同的。也就是說,他們有不同的簽名。在這種情況下,決定在哪個方法調用編譯時間。 (你可以有一個情況,即重載和重載兩者都發生,關於選擇哪個參數簽名的決定是在編譯時做出的;但是如果有多個具有相同簽名的重寫方法,那麼這些方法在運行時就作出選擇。 )

要記住的關鍵是,如果決定是在編譯時做出的,編譯器將而不是知道對象的「真實」類型是什麼。它只知道你是如何宣佈它的。因此:

public CsTorta retegez(CsTorta a){ // Number 1 
    .... 
} 
public CsTorta retegez(Torta a){  // Number 2 
    System.out.println("This method");    //<-----it calls this one and not the one above 
    .... 
} 

這些是重載方法。

代碼如下:

Torta tcs = // the compiler doesn't care 

System.out.println(tcs.retegez(tcs)); 

編譯器必須決定是否要呼叫號碼1或2號。所有的編譯器知道是該參數是一個Torta。實際值可能是TortaCsTorta或任何其他類的對象。或者它可能是null(沒事,你不能稱之爲tcs.retegez如果它是空的,但如果你說tcs.retegez(tcs2),然後tcs2可能是空的。)編譯器不知道,也不關心。它只知道它被聲明爲Torta,所以它選擇了參數爲Torta的重載方法。

(爲了進一步澄清:編譯器會選擇最深的子類,它可以舉例:)

class AnotherTorta extends Torta { ... } 
class YetAnotherTorta extends CsTorta { ... } 

AnotherTorta t3 = // whatever 
YetAnotherTorta t4 = // whatever 

tcs.retegez(t3); 
    // since AnotherTorta can't be cast to CsTorta, it chooses the Torta parameter 
tcs.retegez(t4); 
    // here, t4 can be cast to either a Torta or CsTorta parameter, so it chooses the subclass, CsTorta