《Java編程思想》筆記7.複用類


點擊進入個人博客

複用代碼是Java衆多引人注目的功能之一,但要成爲極具革命性的語言,僅僅可以複製代碼並對之加以改變是不夠的,它還必須可以作更多的事情。ide

7.1 組合

組合語法

就是在當前類中產生現有類的對象。函數

toString()方法

每個非基本類型的對象都有該方法,當編譯器須要一個String但你只有一個對象時,該方法會自動調用。代理

初始化引用

編譯器並非簡單的爲每個引用都建立對象,由於這回增長沒必要要的負擔code

  1. 在定義對象的時候初始化,這意味着在構造方法以前被調用。
  2. 在類的構造方法中。
  3. 就在正常使用這些對象以前——惰性初始化
  4. 使用實例初始化

7.2 繼承

  • 使用extends關鍵字實現繼承
  • 當建立一個類時老是在繼承,除非明確指定從其餘類繼承,不然就是隱式從Object繼承
  • 繼承時會自動獲得基類中全部的域和方法
  • 使用super.func()調用父類中的方法。

7.2.1 初始化基類

  • 當建立類一個子類的對象時,該對象包含了一個基類的自對象。這個子對象與你用基類直接建立的對象是同樣的。兩者區別在於,後者來自於外部,而基類的子對象被包裝在子類對象內部。
  • 對基類子對象對正確初始化:在子類構造器中調用基類構造器。Java會自動在子類構造器中插入對基類構造器對調用。
  • 編譯器強制你去初始化基類,但並不表明會初始化成員對象。
帶參數的構造器
  • 若是基類沒有默認的無參構造器,或者想調用一個帶參數的基類構造器,就必須用關鍵字super顯式地編寫基類構造器的語句。
  • 對基類構造器的調用必須放到子類構造器的第一行。

7.3 代理

  • Java並無提供對代理對直接支持,這是繼承和組合的中庸之道。
  • 代理:將一個成員對象放置於所須要的構造的類中(像組合),但與此同時在新類中暴露該成員對象的相關方法(像繼承)。
  • 使用代理能夠有更多的控制力,由於咱們能夠選擇只暴露一個子集。
public class Test {
    TestDemo demo = new TestDemo();
    // 代理
    public void func() {
        demo.func();
    }
}

class TestDemo {
    void func() {}
}

7.4 結合使用組合和繼承

7.4.1 確保正確清理

  • 通常狀況下,清理並非問題,僅需讓垃圾回收器完成該動做就行。但當必須親自處理清理(如文件的關閉)時,就要多加當心。
  • 由於,垃圾回收器可能永遠也沒法被調用,即時被調用,它是按照任何它想要的順序來回收對象。
  • 最好的辦法是除了內存之外,不能依賴垃圾回收器去作任何事。
  • 若是須要清理,就本身寫一個清理方法,但不要使用finalize()。
  • 清理語句儘可能寫在finally代碼塊中。

7.4.2 名稱屏蔽

  • 若是Java的基類已經擁有某個已被屢次重載的方法,那麼在子類中從新定義該方法名稱並不會屏蔽其在基類中的任何版本。所以,不管是在該層或者它的基類中隊方法進行定義,重載機制均可以正常工做。
  • 可使用@Override來表示要重寫父類方法。

7.5 在組合和繼承間選擇

組合和繼承都容許在新的類中放置子對象,組合是顯式地這樣作,而繼承是隱式地作。對象

繼承很重要可是並不意味着咱們須要經常用他,如何判斷是否應該使用繼承請參照兩個標準:排序

  1. 若是是「is-a」的關係,那就使用繼承。若是是「has-a」的關係,那就使用組合。
  2. 是否須要向上轉型,若是必須向上轉型則必須使用繼承,不然應該慎重考慮

7.6 protected關鍵字

  • 在實際項目中,常常會想要將某些事物儘量對這個世界隱藏起來,但仍容許導出類的成員訪問它們。
  • 儘管能夠建立protected域成員,但最好的方式仍是private,只有在真正須要的時候才使用protected關鍵字。

7.7 向上轉型

  • 「爲新類提供方法」並非繼承技術最重要的方面,其最重要的方面是用來表現子類和基類之間的關係。
  • 子類引用能夠向上轉型成爲基類引用,由於派生類必定具備基類的方法。類接口惟一可能發生的事情是丟失方法,而不是獲取它們。

7.8 final關鍵字

7.8.1 final數據

final變量
  • final基本數據類型:表示數據是不可變的常量
  • final對象引用:引用與對象的關聯關係不可變,但能夠對對象進行操做。
  • final static約定用大寫字母+下劃線命名規範
空白final
  • 空白final指被聲明爲final但又未給定初值的域,但能夠在構造方法
  • 必須在域的定義處、static代碼塊或構造器中對final進行賦值。
final參數
  • Java容許在參數列表中將參數指明爲final
  • 修飾對象參數:意味着沒法在方法中修改參數引用的對象
  • 修飾基本類型:可使用但沒法修改此參數

7.8.2 final方法

  1. 把方法鎖定,禁止繼承類修改它(即不會被重寫)
  2. 在JavaSE5以前,使用final能夠提升效率,但目前已過期
final和private關鍵字
  • 類中全部private方法都隱式的指定是final的,在private方法前添加final是沒有額外意義的。
  • private修飾的方法,不屬於基類接口一部分,他僅僅是隱藏在類中的一部分代碼。所以若是你在導出類中「覆蓋」了基類的private方法,其實並無覆蓋private方法,而產生了一個新方法。

7.8.3 final類

  • final放在class前作修飾,代表該類沒法進行繼承
  • final類中的域和普通類的域並沒有差異
  • final類隱式的將該類中全部的方法指定爲final,因此在final類中給方法添加final關鍵詞沒有意義。

7.8.4 final的忠告

要考慮清楚!!!繼承

7.9 初始化及類的加載

每一個類的編譯代碼.class都存在於獨立的文件中,該文件只在須要的使用程序代碼時纔會被加載。接口

  1. 按照父類到子類的順序加載static變量
  2. 構造子類對象時,先構造父類對象。
public class Test extends TestParents {
    // (a) static屬性
    static String staticProperty;

    // (b) 構造方法
    public Test() {
        System.out.println("Test constructor");
    }

    // (c) static代碼塊
    {
        staticProperty = print("Test static property");
        System.out.println("Test static");
    }
    
    // (d) 非static代碼屬性
    String property = print("Test property");

    public static void main(String[] args) {
        // (1):System.out.println(Test.staticProperty);
        // TestParents static property
        // null(由於static代碼塊中的代碼要建立對象才執行)
        // (2):Test test = new Test();
        // TestParents static property
        // TestParents property
        // TestParents static
        // TestParents constructor
        // Test static property
        // Test static
        // Test property
        // Test constructor
    }
}

class TestParents {
    static String staticProperty = print("TestParents static property");

    String property = print("TestParents property");

    {
        System.out.println("TestParents static");
    }

    public TestParents() {
        System.out.println("TestParents constructor");
    }

    static String print(String str) {
        System.out.println(str);
        return str;
    }
}
靜態代碼塊和靜態變量
  • 靜態變量 >> 靜態代碼塊
代碼塊(注意不是靜態代碼塊)、構造方法、非static屬性
  • 三者順序:代碼塊 == 非static屬性 >> 構造方法;即代碼塊和非static屬性按照代碼中順序排序,構造函數在最後面
  • 上述Test類的代碼,反編譯後的結果以下所示:
public Test()
    {
        staticProperty = print("Test static property");
        System.out.println("Test static");
        property = print("Test property");
        System.out.println("Test constructor");
    }

7.10 總結

優先選擇組合和代理,必要時才使用繼承。內存

相關文章
相關標籤/搜索