回調機制是 Java 異步編程、事件驅動、框架擴展的基石。許多初學者被「誰調用誰」、「接口怎麼定義」繞暈。本文通過一個層層遞進的幼兒園故事,將抽象概念具象化,最後落地到標準的「接口 + 內部類」工程實現。
場景:小明自己心算「1+1=2」並填空。
public class Student {
private String name;
public Student(String name) { this.name = name; }
private int calcAdd(int a, int b) { return a + b; } // 內部實現
public void fillBlank(int a, int b) {
int result = calcAdd(a, b); // 同步調用,阻塞等待
System.out.println(name + "心算: " + a + " + " + b + " = " + result);
}
}
特點:調用者(Student)自包含邏輯,執行路徑單一,無異步、無解耦。
場景:題目變難「168+291」,小明借用計算器對象完成計算。
public class Calculator {
public int add(int a, int b) { return a + b; }
}
public class Student {
// ...
private int useCalculator(int a, int b) {
return new Calculator().add(a, b); // 直接依賴具體類
}
public void fillBlank(int a, int b) {
int result = useCalculator(a, b);
System.out.println(name + "用計算器: " + a + " + " + b + " = " + result);
}
}
進化:計算邏輯分離,但 Student 仍強依賴 Calculator 具體類,且調用同步阻塞。
場景:超難題「26549+16487」,小明把題目和「填空位置」(自身引用)交給小紅,自己去玩。小紅算完後,「回調」小明的填空方法。
// 1. 超級計算器(服務提供方)
public class SuperCalculator {
public void add(int a, int b, Student xiaoming) {
int result = a + b;
xiaoming.fillBlank(a, b, result); // 回調調用
}
}
// 2. 學生(調用方/被回調方)
public class Student {
// ...
public void callHelp(int a, int b) {
new SuperCalculator().add(a, b, this); // 傳遞自身引用
}
public void fillBlank(int a, int b, int result) { // 回調方法
System.out.println(name + "求助小紅: " + a + " + " + b + " = " + result);
}
}
問題:小紅想同時服務小明(學生)和婆婆(攤販),不能強依賴 Student 類。
public interface DoJob {
void fillBlank(int a, int b, int result); // 統一回調方法
}
public class SuperCalculator {
public void add(int a, int b, DoJob customer) {
int result = a + b;
customer.fillBlank(a, b, result); // 面向接口編程
}
}
// 學生端
public class Student {
private String name;
public Student(String name) { this.name = name; }
private class DoHomeWork implements DoJob {
@Override
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 DoHomeWork());
}
}
// 攤販端
public class Seller {
private String name;
// 同理實現 DoJob,邏輯不同(顯示「元」)
}
| 階段 | 關鍵特徵 | 對應技術場景 |
|---|---|---|
| 同步直調 | 調用者包含實現 | 工具類、Utils |
| 委託調用 | 依賴具體協作類 | Service 層調用 Repository |
| 回調模式 | 雙向依賴:調用者傳自身引用,被調用者反向調用 | 事件監聽、異步回調、模板方法、攔截器 |
| 接口回調 | 面向接口解耦,支持多實現 | Listener、Callback 接口、Spring AOP |
DoJob.fillBlank)this 或實現類實例傳給服務方java.util.Comparator:排序時的回調比較邏輯Filter 鏈:doFilter(request, response, chain) 中的 chain.doFilter() 即回調JdbcTemplate:query(sql, new RowCallbackHandler() {...})ChannelFutureListener理解回調,關鍵在於「好萊塢原則」:Don't call us, we'll call you. 服務提供方控制流程,調用者只需提供「完成後該做什麼」的邏輯封裝。