內部類是定義在另一個類內部的類。雖然 Java 開發建議「盡量少用,提取為獨立類」,但理解其機制對閱讀框架源碼、處理回調、事件監聽等場景至關重要。
| 類型 | 定義位置 | 訪問外部成員 | 實例化方式 |
|---|---|---|---|
| 成員內部類 | 類內部、方法外 | 可直接訪問外部類所有成員(含 private) | Outer.Inner in = new Outer().new Inner(); |
| 靜態嵌套類 | 類內部、方法外,加 static | 僅能訪問外部類 static 成員 | Outer.Nested n = new Outer.Nested(); |
| 局部內部類 | 方法/代碼塊內部 | 訪問外部類成員 + final/效果上 final 的局部變量 | 在方法內部 new LocalClass() |
| 匿名內部類 | 表達式中,實現接口/繼承類 | 同局部內部類 | new Interface() { ... } |
本文展示了一個極端的五層嵌套結構,演示如何一層層「向內」實例化:
public class InnerClassTest {
public static void main(String[] args) {
// 1. 外部類實例
InnerClassTest test = new InnerClassTest();
// 2. 一層內部類 A
A a = test.new A();
// 3. A 內部的內部類 B (繼承 A)
A.InnerClassB b = a.new InnerClassB();
// 4. B 內部的內部類 C
A.InnerClassB.InnerClassC c = b.new InnerClassC();
// 5. C 內部的內部類 E
A.InnerClassB.InnerClassC.InnerClassE e = c.new InnerClassE();
// 一行式鏈式寫法
InnerClassE e2 = new InnerClassTest().new A().new InnerClassB().new InnerClassC().new InnerClassE();
}
class A {
class InnerClassB extends A {
class InnerClassC {
class InnerClassE { void eSayHello() {...} }
}
}
class InnerClassD { void dSayHello() {...} }
}
}
outerInstance.new InnerClass()InnerClassB extends A 使其擁有 A 的非私有成員InnerClassB 聲明為 static,則實例化不需 a.new,直接 new A.InnerClassB()編譯器會為非靜態內部類隱式添加構造參數 OuterClass$InnerClass(OuterClass outer),並在構造器首行賦值 this$0 = outer。這就是為什麼非靜態內部類實例會隱式持有外部類引用,可能導致內存洩漏(外部類無法被 GC 回收)。
i am Test,HelloWorld!
i am A,helloworld!
i am B,helloworld
i am C,helloworld!
i am D,Helloworld!
i am E,Helloworld!
======================分隔符====
i am E,Helloworld!
每層內部類成功實例化並調用各自方法,證明鏈式實例化邏輯正確。