簡體   English   中英

為什么這種類型的繼承有效?

[英]Why does this type of inheritance work?

首先我定義超類:

public class Living {
    double energy;

    Living(double energy) {
        this.energy = energy;
    }
}

然后我定義子類:

public class Person extends Living {
    String name;

    Person(double energy, String name) {
        super(energy);  
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public String toString() {
        String s = this.getName() + " " +  this.energy;
        return s;
    }

}

現在,如果我這樣做:

Living creature = new Person(15.2, "Joe");

我將使用Person構造函數創建一個Living類型的生物。 這是允許的,因為PersonLiving的專業化。

但是我仍然無法通過點運算符訪問Person類的方法 - 例如creature.getName() - 因為creature被聲明為Living not Person類型。

System.out.println(creature.getName()); //not possible

但如果我這樣做:

System.out.println(creature.toString());

我明白了

Joe 15.2

因此,不是Living類的toString()方法(不覆蓋),而是調用Person類的toString()方法。 我無法理解為什么會這樣。

我在開頭聲明生物應該是Living類型,盡管我使用Person構造函數。 如果creature沒有name屬性且其toString()方法未被覆蓋,我該如何獲得上述輸出?

該對象確實是Person一個實例,因此具有所有Person方法。 但是,參考文獻是Living類型。 編譯器不知道它的運行時類型,只允許您訪問它“知道”可用的方法 - 即Living類型的方法。

但是,它可以被強制將此變量視為Person ,但顯式轉換:

System.out.println(((Person) creature).getName())

對於每個對象,都有一個表(虛擬表),用於保存有關為此對象定義的方法的信息。

如果在給定對象中覆蓋父方法,則此表將存儲重寫方法的地址,即使該對象被引用為父類之一也是如此。 每次調用方法時,此表用於查找如何訪問該方法。

因此,在您的情況下,它將使用重新定義的方法toString,因為它已替換父方法。

toString()Object中聲明(所有類都繼承自),這就是為什么你可以調用它而不在類Living重寫(有些用於equals()hashCode()等方法)。

注意,如果你在Living的另一個子類上調用toString() ,比如Animal ,它沒有顯式覆蓋toString() ,你將從Object得到一個默認的toString()結果。

public class Animal extends Living {
    String name;

    Person(double energy, String name) {
        super(energy);  
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    // no toString override here

}

Animal上調用toString()

Living animal = new Animal(100, "Fido");
System.out.println(animal.toString()); // something like your.package.Animal@757dbeaf

這是面向對象編程的主要特征之一。

當你做Living creature = new Person(15.2, "Joe"); 你正在定義一個變量,其類型是Living ,但正如你所說,專門作為Person 這意味着它不會有Person方法,只有它的專業化!

所以,例如,如果Living有一個方法

public String getName() {
    return "foobar";
}

你調用了creature.getName() ,返回的不是"foobar" ,而是"Joe" 因為將調用方法的“特化”,而不是超級方法本身。

但是,只能調用“專用”的方法:特定於Person或任何其他子類的方法不能。

對象的類型為Person ,但類型為Living的引用。 由於Living未聲明getName()方法,因此在嘗試調用時會出現編譯錯誤。

所述toString()方法在實際聲明Object ,這是一個隱式的母體Living ,所以toString() 聲明。 由於對象是Person類型,並且它覆蓋toString() ,因此它是被調用的對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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