在Java中,類通常都是獨立存在的,但是我們可以在類中再定義類,這樣的類被稱為內部類。內部類定義位置的不同可以分為成員內部類、靜態內部類、方法內部類、匿名內部類。相對於內部類,包含內部類的類被稱為外部類。
1 內部類的意義
內部類從字面上是非常容易理解的,無非就是在類的內部定義的類。那麼為什麼要在類的內部再定義類呢?
1.私有變量訪問:我們可以把內部類當成外部類的一個成員,內部類對於外部類的其它私有成員變量來說是不受訪問控制權限所影響的。那麼內部類就實現了跨域訪問的特性。
2.隱藏式的多繼承:這個多繼承不同於接口的"多繼承",而是實實在在的多繼承。內部類也是一個單獨類,既然是類就有面向對象的特性,它就可以進行繼承操作,並且內部類的繼承操作對於外部類是否發生過繼承是沒有影響的。這樣內部類和外部類就共同實現了多繼承操作(如果內部類中還有內部類,繼承的個數會被擴大下去)。
3.可以作為抽象類、接口的匿名實現。一些接口和抽象類中的抽象方法非常少,單獨的創建實現子類非常的麻煩,我們就可以通過匿名內部類的方式直接實現接口或者抽象類,這樣能夠簡化類的設計過程。例如Swing中的事件處理、函數式接口都可以直接通過內部類來實現。
2 內部類種類及定義
在定義內部類時,內部類定義的位置不同其意義也不相同。內部類大體上可以分為四種類型:成員內部類,靜態內部類,局部內部類、匿名內部類。其中成員內部類和靜態內部類都是直接定義在外部類中,它們可以作為單獨的類被外部其它類所訪問(受限於訪問修飾符)。局域內部類和匿名內部類定義在方法中,它們並不會被外部的類所訪問,只是一種臨時類。
2.1 成員內部類
成員內部類,直接定義在類的內部,與類的成員變量和方法屬於同一層級。下面代碼是成員內部類的定義示例。
在上述代碼示例中,Inner就是一個內部類,包含Inner類的Outer類我們稱之為外部類。Inner類就是典型的成員內部類。成員內部類可以用常用的四種訪問控制修飾符進行修飾,其訪問控制與成員變量的訪問控制修飾一致。
在其它外圍類中,創建內部類與普通類是相似的,可以直接進行實例化操作。如果在其它外圍類中要完成對內部類Inner的實例創建,必須在外圍類中建立Outer對象,再由Outer對象來創建內部類Inner(如下面代碼所示)。
由於Inner內部類定義時採用了默認的訪問修飾,所以務必保證上述代碼所屬的類與Outer類在同一包中。在外圍類中使用內部類時,要注意內部類的訪問修飾,如果內部類是private修飾的,只能在外部類中使用,其它類是無法聲明內部類的。
2.2 靜態內部類
內部成員類被static修飾就變成了靜態內部類,靜態內部類可以直接進行聲明並實例化(如下面代碼所示)。
在上述代碼中,Inner類就是一個靜態內部類,靜態內部類同樣也可以用四種類型的訪問控制符進行修飾。訪問規則與成員變量訪問控制修飾規則一樣。
外部類對靜態內部類的訪問與成員內部類的訪問方式一樣,直接實例化即可。靜態內部類和成員內部類在使用上的區別主要是在創建過程中存在著差異。
2.3 局部內部類
具備內部類是定義在外部類中的方法中(或流程控制語句中)。局部內部類不能被外部類和外圍類訪問,它只能在定義的局部位置使用(參考局部變量的使用,定義和使用見下面代碼示例)。
在上述代碼示例中,showInner()方法中定義的Inner就是一個方法局部內部類,方法局部內部類只能在方法中使用,出了方法就不能被使用。在showInner2()方法中,Inner2是一個流程控制局部類,它只能在流程內使用。
局部類與局部變量擁有一樣的生命周期,與局部變量一樣,不能被訪問控制修飾符進行修飾。
2.4 匿名內部類
匿名內部類是局部內部類最常用的一種表現形式。匿名內部類只有類的實現體,而沒有類的方法。
我們知道接口(抽象類)是不能直接實例化的,我們必須通過實例化它們的子類來間接的完成接口(抽象類)的實例化。而匿名內部類 相當於我們在使用接口(抽象類)時,臨時創造了一個子類,但是這個子類我們沒有給它命名,我們稱之為匿名類。通常這樣的類是在方法調用過程中創建並使用的(下面代碼演示了匿名內部類的使用)。
在上述示例中,我們在main方法中直接實例化抽象類Animal,在實例化的過程中我們實現了一個匿名的內部類,並將Animal中的抽象方法eat實現。實際上dog對象引用的就是我們創建的匿名內部類。
3 內部類的外部訪問
內部類對外部類可以進行無縫的訪問,無視外部類的訪問修飾。在類的實例方法中,如果類的成員變量和局部變量發生重名衝突時,使用this關鍵字可以表示當前對象。
在內部類中使用"this.變量名"方式表示內部類的成員變量,而外部類的成員變量則用"外部類名.this.變量名"的方式表示外部類的成員變量(如下面代碼所示)。
在上述代碼示例中,內部類getInnerName方法中,我們用this關鍵字對內部類的成員變量進行返回操作,在getOuterName方法中,我們使用Outer.this對外部類的成員變量進行操作。
對於靜態內部類,它的外部訪問比較特殊,靜態內部類只能訪問外部類的靜態變量。而且在非靜態的內部類中,是不能創建靜態的類變量。
每周定時發布2篇基礎技術文章或案例,謝謝關注。