閉包 是攜帶定義環境資訊的可呼叫物件。Java 內部類天然實現閉包:
OuterClass.this)private)這解決了 Java 無指標、需回調機制的痛點:內部類實例攜帶外部上下文,稍後可回呼外部方法。
public class Outer {
private int outerField = 10;
class Inner {
void accessOuter() {
System.out.println(outerField); // 直接存取外部 private
System.out.println(Outer.this.outerField); // 顯式存取
}
}
}
Outer$Inner.classOuter.Inner in = new Outer().new Inner()this.field 為內部,Outer.this.field 為外部public class Outer {
void method() {
class LocalInner { // 方法內部定義
void doSomething() { /* ... */ }
}
// 僅在方法內可用,不可加修飾詞 (public/private/static)
}
}
final 或「實際上 final」區域變數 (Java 8+)public class Outer {
static class Nested {
void staticOnly() { /* 無法存取外部非靜態成員 */ }
}
}
Outer.Nested n = new Outer.Nested()button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { /* 實作 */ }
});
new Thread(() -> {}) (Lambda 替代)、比較器等Writer (作家) 與 Programmer (程式員) 介面皆有 work(),語意不同:
class Writer { void work() { /* 寫作 */ } }
interface Programmer { void work(); }
public class WriterProgrammer extends Writer {
@Override public void work() { /* 寫作實作 */ }
public void code() { /* 寫代碼實作 */ }
// 內部類適配 Programmer 介面
class ProgrammerAdapter implements Programmer {
@Override public void work() { code(); } // 回調外部 code()
}
public Programmer asProgrammer() { return new ProgrammerAdapter(); }
}
外部類直接實作 Writer.work(),內部類適配 Programmer.work() 回調 code(),**單一類別同時滿足兩種介面契約**,無需修改介面定義。
| 陷阱 | 說明 | 建議 |
|---|---|---|
| 記憶體洩漏 | 非靜態內部類實例隱性持有外部引用,外部無法 GC | 靜態內部類 + WeakReference、或 Lambda (無 this 引用) |
| 序列化問題 | 內部類序列化會連帶序列化外部實例 | 避免序列化內部類、或實作自訂序列化 |
| 同名遮蔽混淆 | 內外部同名欄位/方法易誤用 | 顯式用 Outer.this.field、避免同名 |
| 匿名類過度使用 | 邏輯複雜時可讀性差 | 超過 3 行邏輯提取為具名類/Lambda |
this 引用、更簡潔obj::method 替代單方法匿名類record 替代簡單資料載體內部類