Java的四種內部類包括如下:
- 成員內部類
- 靜態內部類
- 局部內部類
- 匿名內部類
成員內部類:
定義在另一個類(外部類)的內部,而且與成員方法和屬性平級叫成員內部類,......相當於外部類的非靜態方法,如果被static修飾,就變成靜態內部類了。
注意事項:
- 成員內部類中不能存在static關鍵字,即,不能聲明靜態屬性、靜態方法、靜態代碼塊等。【非靜態內部類也可以定義靜態成員但需要同時有final關鍵詞修飾,靜態方法鑒於無法用final修飾,仍必須是在靜態內部類 或者非內部類中定義。】
- 創建成員內部類的實例使用:外部類名.內部類名 實例名 = 外部類實例名.new 內部類構造方法(參數),可以理解為隱式地保存了一個引用,指向創建它的外部類對象。
- 在成員內部類中訪問外部類的成員方法和屬性時使用:外部類名.this.成員方法/屬性。
- 內部類在編譯之后生成一個單獨的class文件,里面包含該類的定義,所以內部類中定義的方法和變量可以跟父類的方法和變量相同。例如上面定義的三個類的class文件分別是:MyTest.class、Outer.class和Outer$Inner.class三個文件。
- 外部類無法直接訪問成員內部類的方法和屬性,需要通過內部類的一個實例來訪問。
- 與外部類平級的類繼承內部類時,其構造方法中需要傳入父類的實例對象。且在構造方法的第一句調用“外部類實例名.super(內部類參數)”。
//成員內部類......相當於非靜態方法 class Outer{ private int a = 3; private Inner in; public Outer(){ in = new Inner(); } public int getInnerA(){ return in.a; // 引用內部類的變量,需通過實例 } public class Inner { public int a = 2; public void doSomething() { // 調用外部類的屬性 System.out.println(MemberInner.this.a);// 這塊要注意......很重要!!! System.out.println(a); } } } public class Test3 { public static void main(String[] args) { Outer.Inner inner = new Outer().new Inner();// 非靜態內部類要new實例 inner.doSomething(); } } class Extender extends Outer.Inner{ public Extender(Outer outer){ //外部類實例名.super(內部類參數列表) outer.super(); } }
靜態內部類
使用static修飾的成員內部類叫靜態內部類。
可以這樣理解:與外部類同級的類,或者叫做外部類的靜態成員。與成員內部類的對比如下:
| 說明 |
成員內部類 |
靜態內部類 |
| 靜態成員 |
靜態成員需同時有final關鍵詞修飾 |
可以 |
| 靜態方法 |
不可定義 |
可以 |
| 訪問外部類非static屬性/方法 |
外部類名.this.成員方法/屬性 |
不可以 |
| 外部類訪問內部類 |
需要通過內部類的一個實例來訪問 |
需要通過內部類的一個實例來訪問 |
| 創建實例 |
外部類名.內部類名 實例名 = 外部類實例名.new 內部類構造方法(參數) |
外部類名.內部類名 實例名 = new 外部類名.內部類名(參數) |
| 編譯后的class文件 |
單獨的class文件(so內部類中的方法和變量可以跟父類的方法和變量同名),外部類$內部類.class |
單獨的class文件(so內部類中的方法和變量可以跟父類的方法和變量同名),外部類$內部類.class |
| 其他 |
與外部類平級的類繼承內部類時,其構造方法中需要傳入父類的實例對象。且在構造方法的第一句調用“外部類實例名.super(內部類參數)” |
無 |
局部內部類
定義在代碼塊、方法體內、作用域(使用花括號“{}”括起來的一段代碼)內的類叫局部內部類。
- 局部內部類只能在代碼代碼塊、方法體內和作用域中使用(如創建對象和使用類對象等)
- 局部內部類訪問作用域內的局部變量,該局部變量需要使用final修飾。
- 可以使用abstract修飾,聲明為抽象類。
匿名內部類
匿名內部類定義和實例化形式如下: new 父類構造方法(參數){ //注:該方法名必須在父類中已經存在 修飾符 返回參數類型 方法名(參數列表){ 。。。 } }
- 只能使用一次,創建實例之后,類定義會立即消失(想要多次使用就要用到反射的知識了)
- 必須繼承一個類(抽象的、非抽象的都可以)或者實現一個接口。如果父類(或者父接口)是抽象類,則匿名內部類必須實現其所有抽象方法。
- 不能是抽象類,因為匿名內部類在定義之后,會立即創建一個實例。
- 不能定義構造方法,匿名內部類沒有類名,無法定義構造方法,但是,匿名內部類擁有與父類相同的所有構造方法。
- 可以定義代碼塊,用於實例的初始化,但是不能定義靜態代碼塊。
- 可以定義新的方法和屬性(不能使用static修飾),但是無法顯式的通過“實例名.方法名(參數)”的形式調用,因為使用new創建的是“上轉型對象”(即父類聲明指向子類對象)。
- 是局部內部類,所以要符合局部內部類的要求。
| 說明 |
成員內部類 |
匿名內部類 |
| 靜態成員 |
靜態成員需同時有final關鍵詞修飾 |
不可定義 |
| 靜態方法 |
不可定義 |
不可定義 |
| 訪問外部類非static屬性/方法 |
外部類名.this.成員方法/屬性 |
外部類名.this.成員方法/屬性 |
| 外部類訪問內部類 |
需要通過內部類的一個實例來訪問 |
需要通過內部類的一個實例來訪問 |
| 創建實例 |
外部類名.內部類名 實例名 = 外部類實例名.new 內部類構造方法(參數) |
如上:父類 實例名 = new 父類(){} |
| 編譯后的class文件 |
單獨的class文件(so內部類中的方法和變量可以跟父類的方法和變量同名),外部類$內部類.class |
單獨的class文件,使用類$數字.class |
| 其他 |
與外部類平級的類繼承內部類時,其構造方法中需要傳入父類的實例對象。且在構造方法的第一句調用“外部類實例名.super(內部類參數)” |
無 |
