[英]Overridden and Overloaded Methods
“強制轉換會影響編譯時重載方法的選擇,但不會覆蓋重載方法”是什么意思?
我閱讀了以下有關“重寫的方法和動態綁定”的文章( https://www.oreilly.com/library/view/learning-java-4th/9781449372477/ch06s01.html ),但我聽不懂最后一段
“在上一節中,我們提到了重載方法是由編譯器在編譯時選擇的。另一方面,被覆蓋的方法是在運行時動態選擇的。即使我們創建了一個子類的實例,我們的代碼也從未見過(可能是一個通過網絡加載的新類),它包含的所有覆蓋方法都可以在運行時找到並使用,以替換上次編譯代碼時存在的方法。
相反,如果我們創建一個新的類來實現一個額外的,更具體的,重載的方法,並用它替換我們的類路徑中的已編譯類,則我們的代碼將繼續使用其最初發現的實現。 這種情況將一直持續到我們將代碼與新類一起重新編譯。 這樣做的另一個效果是,強制轉換(即,明確地告訴編譯器將對象視為其可分配類型之一)在編譯時會影響對重載方法的選擇,但不會影響重寫的方法。”
我無法理解“鑄造”這一行:“這的另一個影響是,強制轉換(即,明確地告訴編譯器將對象視為其可分配類型之一)在編譯時會影響重載方法的選擇,但不會影響重載方法的選擇。”
那行指的是
- 方法的重載版本是在編譯時根據傳遞的參數的編譯時類型選擇的; 而
- 根據調用每個方法的對象的類,在運行時選擇覆蓋的方法。
要理解這種區別,請考慮這樣的情況,即同時具有覆蓋和重載。
public class Person {
}
---------------------------------------------------------
public class Postman extends Person {
}
---------------------------------------------------------
public class Dog {
public void barkAt(Person p) {
System.out.println("Woof woof");
}
public void barkAt(Postman p) {
System.out.println("Grrrr");
}
}
---------------------------------------------------------
public class Rottweiler extends Dog {
@Override
public void barkAt(Person p) {
System.out.println("I'm going to eat you.");
}
@Override
public void barkAt(Postman p) {
System.out.println("I'm going to rip you apart.");
}
}
在這種情況下,我們像這樣調用這些barkAt
方法之一。
Dog cujo = new Rottweiler();
Person pat = new Postman();
cujo.barkAt(pat);
現在在這種情況下,是由編譯器選擇cujo.barkAt(pat);
調用諸如public void barkAt(Person p)
或public void barkAt(Postman p)
。 這些方法是彼此的重載。
為此,編譯器查看傳遞給該方法的表達式的類型-即變量pat
。 變量pat
的類型為Person
,因此編譯器選擇方法public void barkAt(Person p)
。
編譯器不會選擇要調用的是Rottweiler
類還是Dog
類中的方法。 這是在運行時發生的,它取決於調用該方法的對象的類 ,而不是基於調用該方法的變量的類型 。
因此,在這種情況下,重要的是稱為cujo
的對象的類。 而在這個例子中, cujo
是Rottweiler
,所以我們得到了該方法的重寫版本-在定義的Rottweiler
類。
這個例子會打印出來I'm going to eat you
。
總結一下:
- 重載是在編譯時根據參數類型選擇的 。
- 覆蓋是在運行時根據對象類選擇的 。
現在,可以使用強制轉換來更改編譯器對重載的選擇。 這是不可能用鑄造改變運行時間選擇替代的。 所以,我們可以寫
cujo.barkAt((Postman) pat);
這次,傳遞給該方法的參數是Postman
類型的表達式。 編譯器會相應地選擇一個重載,這將打印出來, I'm going to rip you apart.
。
強制轉換會影響編譯時重載方法的選擇,但不會影響重載方法的選擇
重載的方法在編譯時可見。 但是,被覆蓋的方法在運行時變得可見。
經驗法則:
Java根據引用變量的內容而不是引用變量的類型來調用重寫的方法。
下面的例子是自我解釋。 希望能幫助到你。
class Animal {
public void speak() {
System.out.print("Animal sounds/roars.");
}
}
class Human extends Animal {
@Override // Method is overridden
public void speak() {
System.out.print("Humans talking english.");
}
public void speak(String words) { // Method is overloaded.
System.out.print("We have brain. We are intelligent."+words);
}
}
class Earth {
public static void main(String a[]) {
Animal a = new Animal();
a.speak(); // Prints Animal sounds/roars.
Human h = new Human();
h.speak(); // Prints "Humans talking english."
Animal a = h; // Cast to superclass reference variable. However, underlying object is of Human.
a.speak(); // Prints "Humans talking english." because speak() is known by Animal at compile time. During runtime,
// the object contains the human object and hence java calls human overridden method.
a.speak("I want to be human."); // Compile time error as speak(..) is not known by Animal at compile time.
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.