C/C++ 通過函數指針實現回調,Java 無方法指針,但接口提供了更安全、更面向對象的等價機制。本文展示標準回調模式:定義接口、事件通知者、事件監聽者三角色協作。
+----------------+ +-------------------+ +------------------+
| EventSource | | CallbackInterface| | EventListener |
| (通知者) |------>| (契約) |<------| (實現者/接收者) |
| | 1.註冊| | 2.實現 | |
| - listeners | | + callback() | | + callback() |
| + addListener | | | | |
| + fireEvent() | | | | |
+----------------+ +-------------------+ +------------------+
| ^ |
| 3. 遍歷 listeners 調用 | |
+--------------------------+-------------------------+
public interface InterestingEvent {
// 可帶參數、可有返回值,視業務而定
void interestingEvent();
}
public class EventNotifier {
private InterestingEvent listener; // 可擴展為 List<InterestingEvent>
private boolean somethingHappened = false;
public EventNotifier(InterestingEvent event) {
this.listener = event;
}
// 業務邏輯觸發點
public void doWork() {
// ... 業務處理 ...
somethingHappened = true; // 條件滿足
if (somethingHappened && listener != null) {
listener.interestingEvent(); // 發起回調
}
}
// 允許運行時更換監聽器
public void setListener(InterestingEvent listener) {
this.listener = listener;
}
}
public class CallMe implements InterestingEvent {
private EventNotifier notifier;
public CallMe(EventNotifier notifier) {
this.notifier = notifier;
// 關鍵:將自身註冊為監聽者
notifier.setListener(this);
}
@Override
public void interestingEvent() {
System.out.println("事件發生!執行回調邏輯...");
// 可訪問外部上下文、更新 UI、觸發後續流程等
}
public void startWork() {
notifier.doWork();
}
}
public class Main {
public static void main(String[] args) {
EventNotifier notifier = new EventNotifier(null); // 稍後設置
CallMe listener = new CallMe(notifier); // 完成雙向綁定
listener.startWork(); // 觸發業務流程 -> 回調
}
}
| 維度 | C/C++ 函數指針 | Java 接口回調 |
|---|---|---|
| 類型安全 | 弱(簽名匹配由程序員保證) | 強(編譯期強制實現接口方法) |
| 上下文攜帶 | 需額外傳遞 void* 用戶數據 | 監聽者對象本身攜帶完整狀態 |
| 多播支持 | 手動維護函數指針數組 | 天然支持 List<Listener> 多播 |
| 內存安全 | 懸空指針風險 | GC 自動管理,無野指針 |
| 匿名內部類/lambda | 不支持 | Java 8+ 支持極簡寫法 |
// 無需顯式實現類
EventNotifier notifier = new EventNotifier(() -> {
System.out.println("Lambda 回調:事件觸發!");
});
notifier.doWork();
配合 @FunctionalInterface 標註,單方法接口即可直接用 Lambda 實現,代碼更緊湊。
private final List<InterestingEvent> listeners = new ArrayList<>();
public void addListener(InterestingEvent l) { listeners.add(l); }
public void removeListener(InterestingEvent l) { listeners.remove(l); }
private void fireEvent() {
for (InterestingEvent l : listeners) l.interestingEvent();
}
interface EventListener {
void onEvent(EventObject e); // 携帶源、時間戳、業務數據
}
class EventObject {
Object source;
long timestamp;
Map<String, Object> data;
}
executor.submit(() -> listener.interestingEvent()); // 非阻塞通知
WeakReference 或及時 removeListenerfireEvent 中捕獲每個監聽器異常,防止單個故障阻斷其他回調EventListenerList、Spring ApplicationEventPublisher、Guava EventBus 等成熟框架Java 通過接口+對象引用優雅地實現了回調模式,比函數指針更安全、更擴展、更符合面向對象原則。從經典匿名內部類到現代 Lambda,回調模式始終是事件驅動、觀察者模式、異步編程的基石。掌握其核心契約與演進寫法,是構建鬆耦合、高內聚 Java 系統的必備技能。