[英]Unclear about dynamic binding
我不理解動態綁定和覆蓋的概念:
這是一些代碼:
class Cake {
public void taste (Cake c) {
System.out.println("In taste of Cake class");
}
}
class ChocolateCake extends Cake {
public void taste(Cake c) {
System.out.println("In taste (Cake version) of ChocolateCake class");
}
public void taste(ChocolateCake cc) {
System.out.println("In taste (ChocolateCake version) of ChocolateCake class");
}
}
public static void main(String[] args)
{
ChocolateCake cc = new ChocolateCake();
Cake c = new ChocolateCake();
Cake c1 = new Cake();
Cake c2 = new ChocolateCake();
c1.taste(cc);
c1.taste(c);
c2.taste(cc);
c2.taste(c);
}
我期望:
In taste of Cake class
In taste of Cake class
In taste (ChocolateCake version) of ChocolateCake class" <----
In taste (Cake version) of ChocolateCake class
實際:
In taste of Cake class
In taste of Cake class
In taste (Cake version) of ChocolateCake class <----
In taste (Cake version) of ChocolateCake class
如果對象是ChocolateCake類型並且我調用cc也是ChocolateCake,那么為什么編譯器會顯示它將Cake作為參數?
這是因為Java在這種情況下使用靜態和動態綁定來選擇要調用的方法。
這條線是這個,對吧?
c2.taste(cc);
編譯器首先選擇要調用的方法(靜態綁定)。 由於c2
是編譯時類型Cake
,編譯器只能看到taste(Cake)
方法。 所以它說“叫taste(Cake)
”。
現在,在運行時,運行時需要根據c2
的運行時類型選擇要調用的taste(Cake)
實現。 這是動態綁定。 它選擇Cake
那個嗎? 還是ChocolateCake
那個? 由於c2
屬於運行時類型ChocolateCake
,因此它在ChocolateCake
調用taste(Cake)
的實現。
正如你所看到的,你認為可以稱之為的方法 - taste(ChocolateCake)
- 甚至沒有提到! 這是因為這是taste
方法的不同重載,因為它在ChocolateCake
類中,編譯器無法看到。 為什么編譯器看不到? 因為c2
是編譯時類型Cake
。
簡而言之,編譯器決定哪個重載,運行時決定哪個實現。
回應你的陳述:
如果對象是ChocolateCake類型...
只有你知道該對象是ChocolateCake
類型。 編譯器沒有。 它只知道c2
是Cake
類型,因為這就是它的聲明所說的。
由於c2
變量的引用類型是Cake
,因此將調用具有Cake
類型參數的taste
方法。
這是因為Cake
類型沒有帶有ChocolateCake
實例的taste
方法,因此您無法從Cake
類型引用變量調用該方法。
其次,在Java中,由於運行時多態性的機制,正在調用ChocolateCake
的重寫taste
方法,而不是在父類Cake
聲明的版本。 這是因為在運行時事實上將會檢查Cake
引用所指向的對象,並且將調用該特定實例的taste
版本。
因此,由於這兩種效果的結合,您可以看到輸出。
如果將c2
的引用類型更改為ChocolateCake
您會看到輸出為:
In taste (ChocolateCake version) of ChocolateCake class
當你調用c2.taste(cc);
因為現在編譯器和運行時都同意特別調用那種taste(ChocolateCake cc)
方法。
在Java中,在c2.taste(cc)
情況下決定調用哪個方法集是在編譯時基於c2
的編譯時類型執行的。 c2
的編譯時類型是Cake
,這意味着對c2
任何方法調用c2
搜索Cake
及其超類,並且不搜索Cake
任何子類(即ChocolateCake
),即使所有子類對編譯器都可見。
在運行時基於接收器和參數的實際運行時類型執行完全動態方法解析的語言,這將使c2.taste(cc)
被解析為ChocolateCake.taste(ChocolateCake cc)
,這種情況很少見,因為它會對運行時性能產生負面影響。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.