動態綁定與靜態綁定
當子類(Y)同時覆蓋了父類(X)的屬性和方法時,爲什麼“X s = new Y(); ”這裏的s只可以調用Y中覆蓋X的方法,而不能使用Y中覆蓋X的屬性。這也是疑惑的關鍵。
我先給出一個結論:父類引用指向子類對象時,父類與子類同名的屬性和方法都會被覆蓋。(一般對屬性的覆蓋叫對屬性的隱藏)
對於上面的結論我們來看你這個程序,既然屬性可以被覆蓋,那怎麼s.i是用了父類的變量值呢?這是關係到了java處理屬性和方法的不同機制引起的。
先再給出一個結論:java對方法的調用是採取動態綁定(運行時才判斷)的方法,對屬性的調用是採取靜態綁定(編譯時就判斷)的方法。
對於上面的結論我們來理解你的程序“X s = new Y(); ”,這一句,也可說是父類引用指向子類對象,也可以說是子類對象向上轉型爲父類引用。那在s使用屬性的時候是靜態綁定的,它是在編譯期就決定了這個屬性是屬於哪一個類的對象了,所以在上面那句中的“X s”也就是說X類中的屬性是用s來調用的,s就不能調用Y類中的屬性,因爲它是靜態綁定了。而s使用方法時是動態綁定的,所以s在調用方法的時候,java會去查看s這個時候的指向的對象是哪一個,是Y類對象就調用Y類的方法,是X類的對象就調用X類的方法。所以這裏s是指向了Y類中的對象(“X s = new Y(); ”這句可知),則調用Y類中的方法。
好,上面對你的問題講清了,下面再說說java因爲什麼對屬性要採取靜態的綁定方法。這是因爲靜態綁定是有很多的好處,它可以讓我們在編譯期就發現程序中的錯誤,而不是在運行期。這樣就可以提高程序的運行效率!而對方法採取動態綁定是爲了實現多態,知道java是的多態是java的一大特色。多態也是面向對象的關鍵技術之一,所以java是以效率爲代價來實現多態這是很值得的。
以下代碼測試:
public class Animal {
public String name="Animal";
publicstaticString id="AnimalID";
public String getName() {
return name;
}
publicvoideat(){
System.err.println("Animal is eating...");
}
}
public classDog extendsAnimal{
public String name="dog";
publicstaticString id="dogID";
public String getName() {
return name;
}
public void eat() {
System.err.println("Dog is eating...");
}
}
public classTest {
public static void main(String[] args) {
Animal an = new Dog();
System.err.println(an.name);
System.err.println(an.id);
System.err.println(an.getName());
an.eat();
}
}
運行結果: