[英]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
類型的生物。 這是允許的,因為Person
是Living
的專業化。
但是我仍然無法通過點運算符訪問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.