Overview
最近在學習Thinking in Java這部java經典,書非常不錯,作者有非常深厚的編程功底,講解知識時候說的很透徹,而且有一定發散,深入淺出,是一本閱讀起來非常舒服。目前閱讀到第八章,除了第五章初始化與清理里的垃圾回收機制有些難度以外,其他章節有一定編程經驗的都可以看懂。從第八章開始,內容開始增多,各種重要知識點開始出現,如不好好總結很可能會漏掉一些細節,所以從這里開始對第八章進行總結。
有關垃圾回收的知識我準備在以后在整理jvm相關知識時再做詳細總結。
Contents
-
初始化的順序
- 先將分配給對象的存儲空間初始化成二進制的零。
- 調用基類的構造器。這個步驟一直遞歸下去,直至遞歸到根類,再開始從根向導出類開始初始化。
- 按聲明順序調用成員的初始化方法。
- 調用導出類構造器的主體。
初始化的順序還要注意在第五章中提到的知識,靜態對象要先于非靜態對象。
- 構造器內部的多態方法的行為
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class JavaTest{
public static void main(String[] args) {
Super sup = new Sub(); //向上轉型
//這里在直接訪問域的時候,并沒有出現理想中的多態
System.out.println("sup.field: " + sup.field + "\nsup.getField: " + sup.getField() + "\n");
Sub sub = new Sub();
System.out.println("sub.field: " + sub.field + "\nsub.getField: " + sub.getField() + "\nsub.getSuperField():" + sub.getSuperField());
}
}
輸出為:
sup.field: 0
sup.getField: 1
sub.field: 1
sub.getField: 1
sub.getSuperField():
當Sub對象轉型為Super引用時,任何域訪問操作都將由編譯器解析,由于多態采用的是動態綁定,而不是靠編譯器,所以無法完成多態。
在上面的例子中,一個sub對象中有兩個叫做field的域(Super.field和Sub.field),然而在引用sub中的field時所產生的默認域并非Super版本的field,因此必須顯示的指明super.field。
在實際編程中非常不贊成出現這樣的代碼,這樣的代碼難以閱讀,進而難以維護。
public class Test1 {
public void printStr(String s){
System.out.println("this is test1.printStr");
System.out.println(s);
}
public void printStr2(String s){
printStr(s);
}
}
public class Test2 extends Test1 {
public void printStr(String s){
System.out.println("this is test2.printStr");
System.out.println(s);
}
public static void main(String[] args) {
Test1 test = new Test2();
test.printStr2("test");
}
}
輸出為:
this is test2.printStr
test
這是第八章練習10的運行效果,和上面的結果放在一起對比看起來會更佳直觀,這里的printStr()方法被覆蓋了,即使是Test1的方法調用printStr()也會調用被覆蓋的方法,與上面的變量覆蓋是不同的。
-
構造器內部的多態方法的行為
- 在Java1.4及以前,子類方法如果要覆蓋超類的某個方法,必須具有完全相同的方法簽名,包括返回值也必須完全一樣。
- Java5.0放寬了這一限制,只要子類方法與超類方法具有相同的方法簽名,或者子類方法的返回值是超類方法的子類型,就可以覆蓋。
- 注意:"協變返回(covariant return)",僅在subclass(子類)的返回類型是superclass(父類)返回類型的extension(繼承)時才被容許。