既然你已經瞭解情況1,3,4,讓我們來解決的情況下2.
(請注意 - 我絕不是在JVM或編譯器的內部工作的專家,但是這是怎麼我明白了,如果有人讀這是一個JVM專家,請隨時編輯這個答案,你可能會發現任何差異。)
一個名稱相同但簽名不同的子類中的方法稱爲方法重載。方法重載使用靜態綁定,這基本上意味着在編譯時將強制適當的方法被「選擇」(即綁定)。編譯器不知道對象的運行時類型(又名實際類型)。所以,當你寫:
// Reference Type // Actual Type
Sub sub = new Sub(); // Sub Sub
Top top = sub; // Top Sub
編譯器只「知道」,頂部是頂部類型(又名引用類型)。所以當你後來寫道:
System.out.println(top.f(str)); // Prints "subobj"
編譯器「看到」調用'top.f'作爲引用Top類的f方法。它「知道」str是擴展Object的String類型。因此,1)調用'top.f'是指Top類的f方法,2)Top類中沒有f方法接受String參數,3)由於str是Object的子類,Top類的f方法是編譯時唯一有效的選擇。所以編譯器隱式地將str上傳到它的父類型Object,所以它可以傳遞給Top的f方法。 (這與動態綁定相反,其中上述代碼行的類型解析將被推遲到運行時,由JVM而不是編譯器來解決)。
然後在運行時,在上面的代碼行中,頂層被JVM貶低爲實際類型sub。但是,參數str已經被編譯器強制轉換爲Object類型。所以現在JVM必須在類sub中調用一個f方法,該方法接受一個Object類型的參數。
因此,上面的代碼行打印「subobj」而不是「sub」。
對於另一個非常類似的例子,請參閱:Java dynamic binding and method overriding
更新:發現了JVM的內部運作這個詳細的文章:
http://www.artima.com/underthehood/invocationP.html
我評論了你的代碼,以使其更清晰發生了什麼:
class Top {
public String f(Object o) {return "Top";}
}
class Sub extends Top {
public String f(String s) {return "Sub";} // Overloading = No dynamic binding
public String f(Object o) {return "SubObj";} // Overriding = Dynamic binding
}
public class Test {
public static void main(String[] args) {
// Reference Type Actual Type
Sub sub = new Sub(); // Sub Sub
Top top = sub; // Top Sub
String str = "Something"; // String String
Object obj = str; // Object String
// At Compile-Time: At Run-Time:
// Dynamic Binding
System.out.println(top.f(obj)); // Top.f (Object) --> Sub.f (Object)
// Dynamic Binding
System.out.println(top.f(str)); // Top.f (Object) --> Sub.f (Object)
// Static Binding
System.out.println(sub.f(obj)); // Sub.f (Object) Sub.f (Object)
// Static Binding
System.out.println(sub.f(str)); // Sub.f (String) Sub.f (String)
}
}
現在我得到了第一行的工作方式,但第二行怎麼會打印出SubObj,即使在把調用是top.f(str)其中str是一種類型的字符串? – user482594 2011-04-14 05:05:04
我發佈了一個答案,你看過它。它應該解決你的疑惑。總結一下從「類型檢查」的角度來考慮傳遞的參數。請接受答案,如果你覺得有幫助.. – 2011-04-14 06:35:26