java允許在一個類別中定義另外一個類,這就叫類嵌套。類別嵌套分為兩種,靜態的稱為靜態巢狀類,非靜態的稱為內部類別。
使用巢狀類別的原因:
能夠將僅在一個地方使用的類別合理地組合。一個類別可能只對於另一個類別有用,此時將前者組合到後者,可以使得程式包更簡潔。
增強封裝性。假如由兩個類A和B,B類需要使用A類中的成員,而恰好該成員又是僅類內部可見的,如果將B定義為A的嵌套類,則B可以使用A的任何成員,而且B也可以聲明為外部不可見。
能夠使程式碼可讀性和維護性更強。嵌套的類別程式碼相較於頂級類,更靠近它被使用的地方,方便查看。
巢狀類別也屬於類別的成員,因此也可使用類別成員的視覺範圍控制修飾詞,內部類別能夠使用其所在類別的其他類別成員,而靜態巢狀類別則不能使用其所在類別的其他類成員。
靜態巢狀類別
與靜態方法與靜態欄位類似,靜態巢狀類別是與其所在類別相關的。靜態嵌套類別不能直接使用實例變數或實例字段,而只能透過一個物件引用,可將靜態嵌套類別視為跟其他頂層類別一樣,只不過是內嵌在其他類別裡面,方便打包。
靜態巢狀類別的使用方法與類別中的其他類別成員類似,一下示範如何建立靜態巢狀類別物件:
//StaticNestedClass为OuterClass的一个嵌套类OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
內部類別(非靜態巢狀類別)
內部類別是與其所在類別的實例相關的 ,能夠直接使用實例物件的方法和字段,內部類別與實例相關,所以內部類別不能定義靜態的成員。
如果需要建立內部類別對象,首先需要建立該內部類別所在的類別的對象,如下所示:
//1创建内部类所在类的对象OuterClass outerObject=new OuterClass();//2创建内部类对象 //注意与静态嵌套类的构造器使用方法的差异OuterClass.InnerClass innerObject = outerObject.new InnerClass();
巢狀類別的遮蔽
當我們聲明一個類型時,如果其名稱與目前程式碼區塊(如一個方法內部)所在的程式碼區塊(如類別內部)內的另一個類型的聲明含有相同的名稱,這種現象就叫遮蔽。當我們需要用到被遮蔽的類型時,我們不能直接引用其名稱,如下例所示:
public class ShadowTest { public int x = 0; //嵌套类 class FirstLevel { //以下声明会遮蔽其所在类的名称为x的字段 public int x = 1; //以下方法的声明会遮蔽其所在类的名称为x的字段 void methodInFirstLevel(int x) { System.out.println("x = " + x); System.out.println("this.x = " + this.x); System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);//注意this关键词的使用方法 } } public static void main(String... args) { ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); } }
上述程式碼輸出為:
x = 23
this.x = 1
ShadowTest.this.x = 0
序列化,教程中強烈建議不要序列化內部類,在此留下疑問。
除了非靜態巢狀類意外,還有兩種內部類,一種是局部類,還有一種是匿名類。
局部類別
局部類別可以在任何程式碼區塊(花括號內)中定義,一般應用於方法之中。
局部類別可以使用其所在頂級類別的類別成員,此外,局部類別也可以使用局部變量,然而,其所使用的局部類別必須有final關鍵字修飾,即不可變變數。在java SE8中,局部類別可以使用本質上不變的局部變量,即該局部變量即便沒有final關鍵字修飾,但實際上從初始化以後,其值從未改變過。
從java8開始,局部類別也可以使用其所在方法的參數。
與內部類別相似,局部類別不能定義靜態成員,在靜態方法中定義的局部類別不能使用實例成員。
在程式碼區塊中不能定義接口,因為接口本質是靜態的。局部類別中也不能定義藉口成員,不過局部類別中可以定義常數變數(用final修飾,類型為基本資料型別或字串,編譯時進行初始化)。
匿名類別
匿名類別能是程式碼更簡潔,它不需要名稱,可以聲明,實例化一步完成。
匿名類別的宣告是一個表達式,如同呼叫一個構造器,不同的是其後還跟上了一個定義類別的程式碼區塊。
匿名類別的定義的表達式包含以下幾個部分:
new關鍵字
一個該匿名類別需要實現的藉口或者是繼承的父類別的名稱
一對圓括號,包含參數,實現一個介面時,參數部分留空
匿名類別主體,跟類別的主體類似, 可以定義方法
匿名類別對於可使用的類型與局部類別相同:
可使用其所在類別的類別成員
可使用其所在程式碼區塊的帶final修飾詞的局部變量,或初始化後不再賦值的局部變數(java8)
對於遮蔽的類型,不能直接用名稱引用
同樣匿名類別不能聲明靜態的成員或接口,但是可以宣告常數變量,在匿名類別的類別主體中,可以聲明實例字段,實例方法,實例初始化程式碼區塊和局部類別。