第八章多態

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(繼承)時才被容許。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.第八章一開頭就說了多態的作用:消除類型之間的耦合關系。 2.多態的前提是繼承與重寫,因為繼承之后允許將子類視為...
    Gzw丶南山閱讀 360評論 0 0
  • 多態分離做什么和怎么做,將接口和實現分離開來。也稱為動態綁定、后期綁定或運行時綁定。
    MAXPUP閱讀 131評論 0 0
  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,778評論 18 399
  • 這兩天正好讀到易中天先生的《帝國的惆悵》中一開篇就講述了關于晁錯的故事,該篇章的標題更有意思,叫做“明月何曾照溝渠...
    正言鋒語閱讀 237評論 0 1
  • 最近一篇網文《羅振宇的騙局》炒的沸沸揚揚,很多人紛紛痛徹心扉,自訴自己花錢學習卻沒有什么卵用。 關于知識的結構太多...
    中大猩猩閱讀 565評論 4 2