簡體   English   中英

覆蓋和重載方法

[英]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的對象的類。 而在這個例子中, cujoRottweiler ,所以我們得到了該方法的重寫版本-在定義的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM