天天看點

【Java程式設計思想讀書筆記】第七章:複用類+第八章:多态

參考書目:《Java程式設計思想》(第四版)

友鍊:​​【讀書筆記】Java重要知識點整理與彙總​​

閱讀《Java程式設計思想》(第四版)一書收獲頗多,之是以想通過用部落格記筆記的方式來讀書,是因為這樣可以倒逼自己仔細、反複地閱讀書中的知識,找相對意義上的重點,并且由于人腦更适合輸出型的學習,通過将内容邊看、邊記、邊了解和邊打字寫文,相比直接反複閱讀更有效益(當然這本書後續仍需反複閱讀幾十遍甚至百遍以上都不為過),而另一個原因就是這樣也能夠在閱讀中通過部落格來記錄自己的學習曆程,部落格記錄的不隻是圖文,它們記錄的正是自己的成長,等以後畢業或者工作後,回首大學四年,多少有點可以回念的東西,還可以說一句:一路走來,我讀了很多前輩們的好書,對技術充滿了熱情,永遠在不斷學習的路上。

start.作者講授思路:

【Java程式設計思想讀書筆記】第七章:複用類+第八章:多态
【Java程式設計思想讀書筆記】第七章:複用類+第八章:多态

1.@Override注解:當你想要覆寫某個方法時,由于不留心導緻重載了該方法而并未覆寫該方法,那麼編譯器回産生一條錯誤資訊。

2.到底是用組合還是用繼承,一個最清晰的判斷辦法就是問一問自己是否需要從新類向基類進行向上轉型,如果必須向上轉型,則繼承是必要的,但如果不需要,則應當好好考慮自己是否需要繼承。

3.類中所有的private方法都隐式地指定為是final的,由于無法取用private方法,也就無法覆寫它,可以對private方法添加final修飾詞,但這并不能給該方法增加任何額外的意義。

4.如果某方法是private,它就不是基類的接口的一部分,它僅是一些隐藏于類中的程式代碼(private方法屬于final方法,并可被自動認為是final方法,對導出類是屏蔽的),隻不過是具有相同名稱而已。但如果在導出類中以相同的方法名稱生成一個public、protected或包通路權限方法的話,該方法就不會産生在基類中出現的“僅具有相同名稱的情況”。此時你并沒有覆寫該方法,僅是産生了一個新的方法。由于private方法無法觸及且能有效隐藏,所有除了把它看成是因為它所歸屬的類的組織結構的原因而存在外,其他任何事物都不需要考慮到它。

5.設計類時,将方法指名是final的,應該說是明智的,這會讓别人不去覆寫你的方法。然而要預見類是如何被複用的一般是困難的,如果考慮不周,可能會妨礙其他程式員通過繼承來複用你的類。

6.在Beetle上運作java時,所發生的第一件事就是試圖通路Beetle.main()(一個static方法),于是加載器開始啟動并找出Bettle類的編譯代碼(在名為Beetle.class的檔案中),在對它進行加載的過程中,編譯器注意到它有一個基類(這是由關鍵字extends得知的),于是會繼續加載這個基類,不管你是否打算産生一個基類的對象,這都要發生。如果基類還有其自身的基類,那麼這個基類的基類也會被加載,以此類推。最終,根基類的static初始化即被執行,然後是它緊接着下面的那個導出類,以此類推,這種方式很重要,因為導出類的static初始化可能會依賴于基類成員能否被正确初始化。

7.設計一個系統時,目标應該是找到或建立某些類,其中每個類都有具體的用途,而且既不會太大(包含太多功能而難以複用),也不會太小(不添加其他方法就無法使用)。如果你的設計變得過于複雜,通過将現有類拆分為更小的部分而添加更多的對象,通常會有所幫助。

8.名詞介紹:

  • 封裝:通過合并特征和行為來建立新的資料類型。
  • 實作隐藏:通過将細節私有化把接口和實作分離開。
  • 多态:用于消除類型之間的耦合關系。
  • 綁定:将一個方法調用同一個方法主體關聯起來。
  • 前期綁定:由編譯器和連接配接程式實作,在程式執行前進行綁定。它是面向過程的語言中不需要選擇就預設的綁定方式。
  • 後期綁定:運作時根據對象的類型進行綁定。也叫做動态綁定或運作時綁定。如果一種語言要實作後期綁定,就必須具有某種機制,以便在運作時能判斷對象的類型,進而調用恰當的方法,也就是說,編譯器一直不知道對象的類型,但是方法調用機制能找到正确的方法體,并加以調用。後期綁定的機制随程式設計語言的不同而有所不同,但不管怎樣都必須在對象中安置某種“類型資訊”。

9.Java中除了static方法和final方法(private方法屬于final方法)之外,其他所有的方法都是後期綁定。是以将一個方法聲明為final時,不僅可以防止他人覆寫該方法,還可以“關閉”動态綁定,這樣,編譯器就可以為final方法調用生成更有效的代碼(Java的早期可以,但如今不需要了,是以最好根據設計來決定是否使用final,而不是出于提高性能的目的)。

9.向上轉型,也就是在繼承層次中向上移動,是安全的,因為基類不會具有大于導出類的接口,是以,通過基類接口發送的消息都能保證被接受。

10.基類的構造器總是在導出類的構造過程中被調用,而且按照繼承層次逐漸向上連結,以使每個基類的構造器都能得到調用。這樣做是有意義的,因為構造器具有一項特殊任務,檢查對象能否被正确地構造。導出類隻能通路自己的成員,不能方法基類的成員(因為通常為private類型)。隻有基類的構造器才具有恰當的知識和權限來對自己的元素進行初始化。是以,必須令所有的構造器都得以調用,否則就不可能正确構造完整對象,這正是編譯器為什麼要強制每個導出類部分都必須調用構造器的原因,在導出類的構造器主體中,如果沒有明确指定調用某個基類構造器,它就會預設調用預設構造器,如果不存在預設構造器,編譯器就會報錯(如果某個類無任何構造器,編譯器就會自動合成出一個預設構造器)。

例子:

class Meal {
    Meal() {
        System.out.println("Meal()");
    }
}

class Bread {
    Bread() {
        System.out.println("Bread()");
    }
}

class Cheese {
    Cheese() {
        System.out.println("Cheese()");
    }
}

class Lettuce {
    Lettuce() {
        System.out.println("Lettuce()");
    }
}

class Lunch extends Meal {
    Lunch() {
        System.out.println("Lunch()");
    }
}

class PortableLunch extends Lunch {
    PortableLunch() {
        System.out.println("PortableLunch()");
    }
}

public class Sandwich extends PortableLunch {
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    public Sandwich() {
        System.out.println("Sandwich()");
    }
    public static void main(String[] args) {
        new Sandwich();
    }
}