通俗來說:你把「做完後該幹什麼」告訴我,我做完後主動通知你。 核心在於「倒置控制」—— 被調用者決定何時調用調用者的代碼。
老師出題:35 + 47 = ?,小明坐著算,算完填空,然後才能去玩。缺點:主線程阻塞,無法做其他事。
小明拿計算器按鍵,得到結果,自己填空。缺點:仍需親自操作工具,還是阻塞。
// 超級計算器(被調用者)
public class SuperCalculator {
public void add(int a, int b, Student xiaoming) {
int result = a + b;
xiaoming.fillBlank(a, b, result); // 回調學生的方法
}
}
// 小明(調用者)
public class Student {
public void callHelp(int a, int b) {
new SuperCalculator().add(a, b, this); // 傳入 this,暴露回調方法
}
public void fillBlank(int a, int b, int result) { // 回調方法
System.out.println("小明請小紅算:" + a + " + " + b + " = " + result);
}
}
關鍵點:小明將 this 傳給計算器,計算器算完後「回調」 fillBlank。小明無需等待,可去玩耍——異步非阻塞。
計算器想服務更多客戶(學生、婆婆、...),不能綁定 Student 類。解決方案:定義介面。
public interface JobCallback {
void fillBlank(int a, int b, int result);
}
// 計算器依賴介面
public class SuperCalculator {
public void add(int a, int b, JobCallback customer) {
int result = a + b;
customer.fillBlank(a, b, result);
}
}
// 學生實現介面(內部類)
public class Student {
public class HomeworkCallback implements JobCallback {
public void fillBlank(int a, int b, int result) {
System.out.println(name + "請小紅算:" + a + " + " + b + " = " + result);
}
}
public void callHelp(int a, int b) {
new SuperCalculator().add(a, b, new HomeworkCallback());
}
}
// 婆婆實現介面
public class Seller {
public class AccountingCallback implements JobCallback {
public void fillBlank(int a, int b, int result) {
System.out.println(name + "請小紅算賬:" + a + " + " + b + " = " + result + "元");
}
}
public void callHelp(int a, int b) {
new SuperCalculator().add(a, b, new AccountingCallback());
}
}
現在,SuperCalculator 只依賴 JobCallback 介面,任何實現該介面的類都能獲得服務——依賴倒置原則 (DIP) 的經典體現。
| 形式 | 典型例子 | 說明 |
|---|---|---|
| 介面回調 | JDBC ResultSet、Servlet Listener、Swing 事件監聽 | 最標準,編譯期類型安全 |
| 匿名內部類 | new Thread(() -> { ... }).start() | 就地定義回調邏輯 |
| Lambda 表達式 | button.addActionListener(e -> doSomething()) | Java 8+,函數式介面簡化語法 |
| Future / CompletableFuture | future.thenAccept(result -> ...) | 異步編程標準化 |
| Observables (RxJava) | observable.subscribe(onNext, onError) | 響應式流 |
回調本質是「將作為參數傳遞的可執行代碼」。從小明的作業到婆婆的算賬,我們看到了:
掌握回調,是理解 Java 異步編程、事件驅動、框架設計(Spring 生命週期、Netty Handler、MyBatis 插件)的關鍵一步。