《Java編程思想》第四版讀書筆記 第十章 內部類

內部類和組合的概念徹底不一樣。最初,內部類看起來就像是一種代碼隱藏機制:將類置於其餘類的內部。可是,內部類遠不止如此,它瞭解外圍類,並能與之通訊;並且用內部類寫出的代碼更加優雅而清晰。java

10.1閉包

若是想從外部類的非靜態方法以外的任意位置建立內部類的對象,那麼必須具體指明這個對象的類型:OuterClass.InnerClass。個人理解:內部類的對象能夠看做是和外部類的對象相聯的。沒有外部類的對象,沒法建立內部類的對象。函數

10.2測試

內部類的對象只能在與其外圍類的對象相關聯的狀況下才能被建立,構建內部類對象時,須要一個指向其外圍類對象的引用。this

10.3編碼

在內部類中若是想使用外部類對象的引用,可使用"OuterClass.this"的形式。此引用自動的具備正確的類型,這一點在編譯期被知曉並受到檢查,所以沒有任何運行時開銷。spa

若是想要告知某些其餘對象,去建立某個內部類的對象,必須在new表達式中提供對其外部類對象的引用:指針

Outer outer = new Outer();code

outer.new Inner();對象

要想直接建立內部類的對象,不能引用外部類的名字,而必須使用外部類的對象來建立該內部類對象。在擁有外部類對象以前是不可能建立內部類對象事務。這是由於內部類對象會暗暗地鏈接到建立它的外部類對象上。可是若是建立的是嵌套類(靜態內部類),就不須要外部類對象的引用。

10.4

練習6中在類中的一個protected內部類,在另外包的類中是沒法建立對象的,由於該內部類的構造函數和內部類擁有相同的訪問屬性,即protected。解決方法是顯示寫出內部類的構造函數,並把它設置爲public。

此處須要注意的特性是,內部類的構造函數和內部類具備相同的訪問屬性

練習8告訴咱們,外部類能夠訪問內部類的private域和方法。內部類和外部類的訪問權限是雙向的。

10.5

能夠在一個方法裏或者在任意的做用域內定義內部類。這麼作有兩個理由:

(1)實現了某個接口,因而能夠建立並返回對其的引用;

(2)要解決一個複雜的問題,想建立一個類來輔助,但又不但願這個類是公共可用的。

個人理解:這種在方法或做用域中的內部類與其餘類一塊兒被編譯,並非說只有到做用域裏才編譯。可是,它們只在做用域中可見。

匿名類不可能有構造函數。

10.6

若是定義一個匿名內部類,而且但願它使用一個在其外部定義的對象,那麼編譯器會要求其參數引用是final的。

因爲匿名內部類沒有構造函數,能夠用語句塊的形式對類的對象進行初始化。

練習12 要求在沒有指定實現的接口或繼承的基類的狀況下返回一個匿名內部類,這時可用Object做爲引用:

public Object getInnerClass() {   
    return new Object() {
       ...
    }
}

運用匿名內部類,修改接口那一章的工廠方法,使代碼變得更整潔優雅:

10.7

靜態的內部類也沒稱爲嵌套類,它與普通內部的區別:

(1)要建立嵌套類的對象,並不須要外圍類的對象;

(2)不能從嵌套類的對象中訪問非靜態的外圍類數據;

(3)嵌套類能夠有static方法和域,還能夠有嵌套類,普通內部類不能夠。

練習18 要求建立一個嵌套類並在main函數中建立其實例。答案說,若是在外圍類中使用嵌套類,直接使用類名就能夠,可是若是在其餘地方使用嵌套類,則必須使用「外圍類.嵌套類」的形式。通過代碼測試,其實直接「import 外圍類.嵌套類」也能夠在其餘地方使用嵌套類。

接口中能夠包含嵌套類。放到接口中的任何類都自動的是public和static的。由於類是static的,只是將嵌套類置於接口的命名空間內,並不違反接口的規則。甚至能夠在嵌套類中實現其外圍接口。若是想要建立某些公共代碼,使得它們能夠被某個接口的全部不一樣實現所共有,那麼使用接口內部的嵌套類會很方便。

做者還提到了一個技巧:

他建議在每一個類中都寫一個主函數用來測試這個類。這樣有一個缺點,是必須帶有這些額外的測試代碼。可使用嵌套類來放置主函數和測試代碼。好比在類TestBed中建立Tester嵌套類,包含主函數和測試代碼。那麼編譯器會生成一個獨立的類TestBed$Tester,要運行這個程序,執行java TestBed$Tester(Unix/Linux系統中須要轉義$)。當發佈產品的時候,簡單的刪除TestBed$Tester.class文件便可。

經編碼測試接口中的嵌套類是不會繼承到它的實現中的。

10.7.2小節主要講了,多層內部類,不論層數有多少,它都能透明的訪問全部外圍類。我的認爲這個討論不該放在10.7中,由於本節主要講述嵌套類(即靜態的內部類),而此處說的是普通內部類,容易形成混淆。此處應注意,10.7.2小節討論的是普通內部類的嵌套,而不是嵌套類。

10.8

使用內部類的一個主要緣由是每一個內部類都能獨立的繼承一個類,而不管外圍類是否已經繼承了某個類。這樣內部類和接口一塊兒構成了多重繼承的解決方案。

還有其餘一些特性:

(1)內部類能夠有多個實例,每一個實例都有本身的狀態信息,而且與其外圍類對象的信息相互對立;

(2)在單個外圍類中,可讓多個內部類以不一樣的方式實現同一個接口,或繼承同一個類;

(3)書中有些迷惑。英語原話是:The point of creation of the inner-class object is not tied to the creation of the outer-class object. 個人理解是,內部類對象建立的時間點不與外部類對象的建立綁定在一塊兒。這應該是相對於導出類與基類的關係來講的(由於導出類的對象建立時基類的對象也將建立);

(4)內部類並無使人迷惑的「is-a」關係,它是一個獨立的實體。

閉包是一個可調用的對象,它記錄了一些信息,這些信息來自於建立它的做用域。按照這個定義,內部類是一種面向對象的閉包。

回調機制中的對象攜帶一些信息,這些信息容許它在稍後的某個時刻調用初始的對象。C++中經過函數指針能夠實現回調,而Java經過內部類提供的閉包功能來實現回調。回調的價值在於它的靈活性——能夠在運行時動態的決定須要調用什麼方法。在實現GUI功能的時候,處處都用到了回調。

10.9

繼承內部類時,語法比較特殊:

class WithInner {
     class Inner {
     }
}

public class InheritInner extends WithInner.Inner {
    //默認的構造方法不會編譯經過
    //構造函數必須有一個外部類的引用參數
    public InheritInner(WithInner wi){
        wi.super(); //個人理解:能夠看作是顯示的調用Inner的構造函數
    }
}

10.10

當繼承了某個外圍類的時候,內部類並無發生什麼變化。這兩個內部類是徹底獨立的兩個實體,各自在本身的命名空間內。

10.11

方法或做用域內的內部類(局部內部類)能夠訪問當前代碼塊內的常量以及外圍類的全部變量。

既然局部內部類的名字在做用域外是不可見的,那爲何不適用匿名內部類?有兩個緣由:

(1)須要構造函數;

(2)須要多個該內部類的實例。

10.12

每一個類會產生一個.class文件,其中包含了如何建立該類型對象的所有信息(此信息產生一個meta-class,叫作Class對象)。內部類的命名規則:外圍類的名字加上$,再加上內部類的名字。若是內部類是匿名的,編譯器會簡單的產生一個數字做爲其標識符。

相關文章
相關標籤/搜索