閉包是一個可調用對象,記錄創建時作用域的信息。Java 中內部類本質上就是面向對象的閉包——它不僅包含外圍類對象信息,還自動持有對外圍類對象的引用,可訪問所有成員(含 private)。
interface Incrementable {
void increment();
}
class MyIncrement {
void increment() { System.out.println("other increment"); }
static void f(MyIncrement mi) { mi.increment(); }
}
class Callee2 extends MyIncrement {
private int i = 0;
private void incr() { i++; System.out.println(i); }
// 內部類實現 Incrementable,避開繼承衝突
private class Closure implements Incrementable {
public void increment() { incr(); }
}
Incrementable getCallbackReference() {
return new Closure(); // 返回內部類實例作為回調鉤子
}
}
class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) { callbackReference = cbh; }
void go() { callbackReference.increment(); }
}
public class Callbacks {
public static void main(String[] args) {
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2();
MyIncrement.f(c2); // 輸出: other increment
Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference()); // 獲得 Closure 實例
caller1.go(); // 1
caller1.go(); // 2
caller2.go(); // 1
caller2.go(); // 2
}
}
| 特性 | 說明 |
|---|---|
| 解決繼承衝突 | 外部類已有同名方法時,內部類可獨立實現接口 |
| 安全的回調鉤子 | 調用者僅持有接口引用,只能調用 increment(),無法訪問其他內部狀態 |
| 封裝性 | Closure 為 private,外部不可直接實例化 |
| 狀態捕獲 | 內部類自動捕獲外部類實例引用,可訪問 incr() 等私有成員 |
final 或實際上 final 的局部變量// Java 8+ 寫法
Caller caller2 = new Caller(c2::incr); // 方法引用
// 或
Caller caller2 = new Caller(() -> c2.incr()); // Lambda
理解內部類閉包機制,是掌握 Java 回調、事件驅動、函數式編程的基石。