Reactor 事件流 vs. Spring 事件 (ApplicationEvent)

Reactor 事件流 vs. Spring 事件 ApplicationEvent

  • Reactor 事件流 vs. Spring 事件 (`ApplicationEvent`)
    • 1?? 核心區別
    • 2?? Spring 事件 (`ApplicationEvent`)
      • ? 示例:Spring 事件發布 & 監聽
        • 1?? 定義事件
        • 2?? 發布事件
        • 3?? 監聽事件
        • 🔹 進階:異步監聽
    • 3?? Reactor 事件流(`Flux` / `Mono` / `Sinks.Many`)
      • ? 示例:事件流處理
        • 1?? 冷流(每個訂閱者獨立獲取數據)
          • ? 方法 1:使用 `Flux.create()`,手動推送數據
          • **? 方法 2:使用 `Flux.generate()`,按需推送數據**
          • **? 方法 3:使用 `Sinks.many().multicast()`,支持多個訂閱者**
          • **? 結論**
        • 2?? 熱流(共享事件流)
        • **📌 ReplayProcessor:可重放歷史事件的 Reactor 處理器**
        • **📌 1?? 關鍵特點**
        • **📌 2?? 基本使用**
        • **📌 運行結果**
        • **📌 3?? `ReplayProcessor` vs `Sinks.Many`**
        • **📌 4?? 適用場景**
    • 4?? 什么時候用哪個?
    • 5?? 總結

Reactor 事件流 vs. Spring 事件 (ApplicationEvent)

1?? 核心區別

特性Spring ApplicationEventReactor Flux /Sinks.Many
數據處理方式一次性事件(同步或異步)流式處理(持續事件流)
是否支持多個訂閱者? 支持(多個 @EventListener? 支持(Sinks.Many 廣播)
是否支持流式操作? 不支持? 支持map(), filter(), zip()
是否支持回放歷史事件? 不支持?(默認不支持,但可用 ReplayProcessor
適用場景業務事件通知(用戶注冊、訂單支付)高吞吐數據流處理(日志、消息隊列、WebFlux)

2?? Spring 事件 (ApplicationEvent)

🔹 特點

  • 適用于應用內部組件通信,解耦業務邏輯。
  • 默認同步,可使用 @Async 進行異步處理。
  • 一次性事件,無法流式處理。

? 示例:Spring 事件發布 & 監聽

1?? 定義事件
public class UserRegisteredEvent extends ApplicationEvent {private final String username;public UserRegisteredEvent(Object source, String username) {super(source);this.username = username;}public String getUsername() { return username; }
}
2?? 發布事件
@Component
public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void registerUser(String username) {eventPublisher.publishEvent(new UserRegisteredEvent(this, username));}
}
3?? 監聽事件
@Component
public class WelcomeEmailListener {@EventListenerpublic void handleUserRegisteredEvent(UserRegisteredEvent event) {System.out.println("📧 發送歡迎郵件給: " + event.getUsername());}
}

可多個 @EventListener 監聽同一個事件,同時觸發

@Component
public class LoggingListener {@EventListenerpublic void logUserRegisteredEvent(UserRegisteredEvent event) {System.out.println("📜 記錄日志: 用戶 " + event.getUsername() + " 已注冊");}
}
@Component
public class PointsRewardListener {@EventListenerpublic void giveWelcomePoints(UserRegisteredEvent event) {System.out.println("🎁 贈送 100 積分給: " + event.getUsername());}
}
🔹 進階:異步監聽

🔹 1?? 監聽器可以指定異步 需要啟用 Spring 異步,@EnableAsync

@Async
@EventListener
public void sendWelcomeEmail(UserRegisteredEvent event) {System.out.println("📧 發送歡迎郵件給: " + event.getUsername() + " [異步]");
}

🔹 2?? 監聽多個事件 如果多個事件需要相同的處理邏輯,你可以用 classes 監聽多個事件:

@EventListener(classes = {UserRegisteredEvent.class, OrderPlacedEvent.class})
public void handleMultipleEvents(Object event) {System.out.println("📢 事件觸發: " + event.getClass().getSimpleName());
}

🔹 3?? 條件監聽 可以使用 condition 屬性,讓監聽器只處理 符合條件 的事件:

@EventListener(condition = "#event.username.startsWith('A')")
public void handleUserStartingWithA(UserRegisteredEvent event) {System.out.println("🎯 處理用戶名以 A 開頭的用戶: " + event.getUsername());
}

🔹 適用場景 ? 適用于業務事件通知(如用戶注冊、訂單支付)。 ? 不適用于流式數據處理

3?? Reactor 事件流(Flux / Mono / Sinks.Many

🔹 特點

  • 異步 & 流式 處理,可以并行、合并、過濾、轉換數據。
  • 冷流(Flux、Mono) 每個訂閱者獨立處理數據
  • 熱流(Sinks.Many) 可用于事件廣播

? 示例:事件流處理

1?? 冷流(每個訂閱者獨立獲取數據)
Flux<String> flux = Flux.just("事件1", "事件2", "事件3");
flux.subscribe(event -> System.out.println("訂閱者 1 收到: " + event));
flux.subscribe(event -> System.out.println("訂閱者 2 收到: " + event));
? 方法 1:使用 Flux.create(),手動推送數據
 import reactor.core.publisher.Flux;
import reactor.core.publisher.FluxSink;import java.time.Duration;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;public class CustomFluxExample {public static void main(String[] args) throws InterruptedException {Flux<String> customFlux = Flux.create(emitter -> {Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {String event = "自定義事件:" + System.currentTimeMillis();System.out.println("發布:" + event);emitter.next(event);}, 0, 1, TimeUnit.SECONDS);}, FluxSink.OverflowStrategy.BUFFER);// 訂閱者 1customFlux.subscribe(event -> System.out.println("訂閱者 1 收到:" + event));Thread.sleep(5000); // 5 秒后再添加訂閱者// 訂閱者 2customFlux.subscribe(event -> System.out.println("訂閱者 2 收到:" + event));Thread.sleep(10000); // 讓主線程等待一會兒,看效果}
}

🔹 運行結果

python-repl復制編輯發布:自定義事件:1712101234567
訂閱者 1 收到:自定義事件:1712101234567
發布:自定義事件:1712101235567
訂閱者 1 收到:自定義事件:1712101235567
發布:自定義事件:1712101236567
訂閱者 1 收到:自定義事件:1712101236567
發布:自定義事件:1712101237567
訂閱者 1 收到:自定義事件:1712101237567
發布:自定義事件:1712101238567
訂閱者 1 收到:自定義事件:1712101238567
(5 秒后,訂閱者 2 加入)
訂閱者 2 收到:自定義事件:1712101239567
訂閱者 1 收到:自定義事件:1712101239567
發布:自定義事件:1712101240567
訂閱者 2 收到:自定義事件:1712101240567
訂閱者 1 收到:自定義事件:1712101240567
...

📌 特點

  1. 你可以隨時手動推送數據(每 1 秒發布一次)。

  2. 新訂閱者不會收到歷史數據,只會接收到之后的事件(如果你想讓新訂閱者也能收到歷史數據,可以用 .replay())。

    示例:

    Flux<String> flux = Flux.just("事件A", "事件B", "事件C").replay(2)  // 緩存最后 2 個事件.autoConnect();  // 至少一個訂閱者連接后開始發布flux.subscribe(event -> System.out.println("訂閱者 1 收到: " + event));// 新的訂閱者會從緩存中接收事件
    flux.subscribe(event -> System.out.println("訂閱者 2 收到: " + event));

    輸出:

    訂閱者 1 收到: 事件A
    訂閱者 1 收到: 事件B
    訂閱者 1 收到: 事件C
    訂閱者 2 收到: 事件B
    訂閱者 2 收到: 事件C
    
  3. 不會自動結束,Flux 會一直運行

? 方法 2:使用 Flux.generate(),按需推送數據

如果你的數據是基于前一個數據計算出來的,可以使用 Flux.generate()

import reactor.core.publisher.Flux;import java.time.Duration;
import java.util.concurrent.atomic.AtomicInteger;public class GenerateFluxExample {public static void main(String[] args) throws InterruptedException {Flux<String> generatedFlux = Flux.generate(() -> new AtomicInteger(1),  // 初始狀態(state, sink) -> {String event = "事件 " + state.getAndIncrement();System.out.println("發布:" + event);sink.next(event);try { Thread.sleep(1000); } catch (InterruptedException e) {}return state;});// 訂閱者 1generatedFlux.subscribe(event -> System.out.println("訂閱者 1 收到:" + event));Thread.sleep(5000); // 5 秒后再添加訂閱者// 訂閱者 2generatedFlux.subscribe(event -> System.out.println("訂閱者 2 收到:" + event));Thread.sleep(10000);}
}

🔹 運行結果

python-repl復制編輯發布:事件 1
訂閱者 1 收到:事件 1
發布:事件 2
訂閱者 1 收到:事件 2
發布:事件 3
訂閱者 1 收到:事件 3
發布:事件 4
訂閱者 1 收到:事件 4
發布:事件 5
訂閱者 1 收到:事件 5
(5 秒后,訂閱者 2 加入)
發布:事件 6
訂閱者 1 收到:事件 6
訂閱者 2 收到:事件 6
發布:事件 7
訂閱者 1 收到:事件 7
訂閱者 2 收到:事件 7
...

📌 區別

  • Flux.generate() 一次只能推送一個數據,適合基于狀態逐步生成數據
  • Flux.create() 可以異步推送多個數據,適合事件流、網絡請求等異步數據
? 方法 3:使用 Sinks.many().multicast(),支持多個訂閱者

如果你希望多個訂閱者可以同時消費,并且可以隨時加入

import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;import java.time.Duration;public class SinkExample {public static void main(String[] args) throws InterruptedException {Sinks.Many<String> sink = Sinks.many().multicast().onBackpressureBuffer();Flux<String> flux = sink.asFlux();// 訂閱者 1flux.subscribe(event -> System.out.println("訂閱者 1 收到:" + event));// 模擬定時推送數據new Thread(() -> {int i = 1;while (true) {String event = "事件 " + i++;System.out.println("發布:" + event);sink.tryEmitNext(event);try { Thread.sleep(1000); } catch (InterruptedException e) { }}}).start();Thread.sleep(5000); // 5 秒后再添加訂閱者// 訂閱者 2flux.subscribe(event -> System.out.println("訂閱者 2 收到:" + event));Thread.sleep(10000);}
}

🔹 運行結果

python-repl復制編輯發布:事件 1
訂閱者 1 收到:事件 1
發布:事件 2
訂閱者 1 收到:事件 2
發布:事件 3
訂閱者 1 收到:事件 3
發布:事件 4
訂閱者 1 收到:事件 4
發布:事件 5
訂閱者 1 收到:事件 5
(5 秒后,訂閱者 2 加入)
發布:事件 6
訂閱者 1 收到:事件 6
訂閱者 2 收到:事件 6
發布:事件 7
訂閱者 1 收到:事件 7
訂閱者 2 收到:事件 7
...

📌 特點

  • Sinks.many().multicast() 允許多個訂閱者同時消費
  • 適用于 WebSocket、事件總線、消息隊列等場景

? 結論
方式特點適用場景
Flux.create()手動推送數據,支持異步適合事件流、消息隊列、WebSocket
Flux.generate()按需推送,每次一個適合基于前一個狀態生成新數據
Sinks.many().multicast()支持多個訂閱者,實時推送適合多訂閱者共享數據
2?? 熱流(共享事件流)
Sinks.Many<String> sink = Sinks.many().multicast().onBackpressureBuffer();
Flux<String> hotFlux = sink.asFlux();hotFlux.subscribe(event -> System.out.println("訂閱者 1 收到: " + event));
hotFlux.subscribe(event -> System.out.println("訂閱者 2 收到: " + event));sink.tryEmitNext("全局事件 1");
sink.tryEmitNext("全局事件 2");

🔹 適用場景 ? 適用于高吞吐、異步、多訂閱者的事件流。 ? 適用于數據流式處理(如 WebFlux、消息隊列、日志流)。 ? 不適用于簡單的業務事件通知

📌 ReplayProcessor:可重放歷史事件的 Reactor 處理器

ReplayProcessor<T> 是 Reactor 提供的一種 熱流(Hot Publisher),它允許新的訂閱者 回放之前發送的事件。適用于 日志系統、消息隊列、數據緩存 等場景。


📌 1?? 關鍵特點

? 存儲歷史事件,新的訂閱者可以看到之前的事件。
? 類似 RxJava 的 ReplaySubject,可以 指定緩存大小
? 適用于需要回放數據的場景,如 日志系統、WebSocket 消息隊列


📌 2?? 基本使用
import reactor.core.publisher.ReplayProcessor;public class ReplayProcessorExample {public static void main(String[] args) {// 創建 ReplayProcessor,緩存 2 條數據ReplayProcessor<String> processor = ReplayProcessor.create(2);// 訂閱者 1 訂閱processor.subscribe(data -> System.out.println("訂閱者 1 收到:" + data));// 發送數據processor.onNext("事件 A");processor.onNext("事件 B");processor.onNext("事件 C");// 訂閱者 2 訂閱processor.subscribe(data -> System.out.println("訂閱者 2 收到:" + data));// 發送更多數據processor.onNext("事件 D");}
}
📌 運行結果
mathematica復制編輯訂閱者 1 收到:事件 A
訂閱者 1 收到:事件 B
訂閱者 1 收到:事件 C
訂閱者 2 收到:事件 B  // 只回放最近 2 條(事件 B 和 C)
訂閱者 2 收到:事件 C
訂閱者 1 收到:事件 D
訂閱者 2 收到:事件 D

📌 說明

  • ReplayProcessor.create(2) 最多緩存 2 條數據,新訂閱者只能收到最近的 2 條事件。
  • 訂閱者 1 先訂閱,它會收到所有事件。
  • 訂閱者 2 后訂閱,但它可以收到最近的 2 條緩存(事件 B 和 C)。

📌 3?? ReplayProcessor vs Sinks.Many
特性ReplayProcessorSinks.Many(Multicast)
是否緩存歷史數據? ,可指定緩存大小? ,不會緩存歷史數據
新訂閱者是否能收到舊數據? 可以? 不能
適用場景回放數據,如日志、歷史消息實時消息推送,不存儲歷史

📌 4?? 適用場景

? 日志回放(新訂閱者也能看到之前的日志)。
? 聊天系統(新加入的用戶可以看到最近的聊天記錄)。
? 數據緩存(保存最近 N 條數據,避免重復請求)。

🚀 如果你需要 緩存歷史數據,并讓新的訂閱者能收到過去的事件ReplayProcessor 是一個很好的選擇!

4?? 什么時候用哪個?

? 使用 ApplicationEvent(Spring 事件)

  • 簡單的應用事件通知(如用戶注冊、郵件通知、訂單完成)。
  • 解耦業務邏輯,但不需要流式處理

? 使用 Reactor 事件流

  • 高吞吐、并發的數據流(日志流、消息流、WebFlux)。
  • 多個訂閱者同時消費事件,如廣播消息、實時數據推送

? 結合使用(最佳實踐)

@EventListener
public void handleUserRegisteredEvent(UserRegisteredEvent event) {Flux.just(event).map(e -> "處理事件: " + e.getUsername()).doOnNext(System.out::println).subscribe();
}

5?? 總結

方案訂閱者是否獨立事件是否廣播適用場景
Spring ApplicationEvent? 每個訂閱者獨立? 不是廣播業務事件通知
Reactor Flux(冷流)? 每個訂閱者獨立? 不是廣播流式數據處理
Reactor Sinks.Many(熱流)? 共享數據流? 所有訂閱者都收到事件驅動架構

🚀 如果你是做 WebFlux、日志流、消息隊列,選 Reactor!如果是應用內部事件解耦,選 Spring ApplicationEvent 🎯

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/75376.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/75376.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/75376.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JVM生產環境問題定位與解決實戰(六):總結篇——問題定位思路與工具選擇策略

本文已收錄于《JVM生產環境問題定位與解決實戰》專欄&#xff0c;完整系列見文末目錄 引言 在前五篇文章中&#xff0c;我們深入探討了JVM生產環境問題定位與解決的實戰技巧&#xff0c;從基礎的jps、jmap、jstat、jstack、jcmd等工具&#xff0c;到JConsole、VisualVM、MAT的…

【5090d】配置運行和微調大模型所需基礎環境【一】

RuntimeError: Failed to import transformers.integrations.bitsandbytes because of the following error (look up to see its traceback): No module named triton.ops 原因&#xff1a;是因為在導入 transformers.integrations.bitsandbytes 時缺少必要的依賴項 triton.op…

華為交換綜合實驗——VRRP、MSTP、Eth-trunk、NAT、DHCP等技術應用

一、實驗拓撲 二、實驗需求 1,內網Ip地址使用172.16.0.0/16分配 2,sw1和SW2之間互為備份 3, VRRP/STP/VLAN/Eth-trunk均使用 4,所有Pc均通過DHCP獲取IP地址 5,ISP只能配置IP地址 6,所有電腦可以正常訪問IsP路由器環回 三、需求分析 1、設備連接需求 二層交換機&#xff08;LS…

DeepSeek 開源的 3FS 如何?

DeepSeek 3FS&#xff08;Fire-Flyer File System&#xff09;是一款由深度求索&#xff08;DeepSeek&#xff09;于2025年2月28日開源的高性能并行文件系統&#xff0c;專為人工智能訓練和推理任務設計。以下從多個維度詳細解析其核心特性、技術架構、應用場景及行業影響&…

Qt實現HTTP GET/POST/PUT/DELETE請求

引言 在現代應用程序開發中&#xff0c;HTTP請求是與服務器交互的核心方式。Qt作為跨平臺的C框架&#xff0c;提供了強大的網絡模塊&#xff08;QNetworkAccessManager&#xff09;&#xff0c;支持GET、POST、PUT、DELETE等HTTP方法。本文將手把手教你如何用Qt實現這些請求&a…

echarts+HTML 繪制3d地圖,加載散點+散點點擊事件

首先&#xff0c;確保了解如何本地引入ECharts庫。 html 文件中引入本地 echarts.min.js 和 echarts-gl.min.js。 可以通過官網下載或npm安裝&#xff0c;但這里直接下載JS文件更簡單。需要引入 echarts.js 和 echarts-gl.js&#xff0c;因為3D地圖需要GL模塊。 接下來是HTM…

深度剖析 MySQL 與 Redis 緩存一致性:理論、方案與實戰

在當今的互聯網應用開發中&#xff0c;MySQL 作為可靠的關系型數據庫&#xff0c;與 Redis 這一高性能的緩存系統常常協同工作。然而&#xff0c;如何確保它們之間的數據一致性&#xff0c;成為了開發者們面臨的重要挑戰。本文將深入探討 MySQL 與 Redis 緩存一致性的相關問題&…

DAO 類的職責與設計原則

1. DAO 的核心職責 DAO&#xff08;Data Access Object&#xff0c;數據訪問對象&#xff09;的主要職責是封裝對數據的訪問邏輯&#xff0c;但它與純粹的數據實體類&#xff08;如 DTO、POJO&#xff09;不同&#xff0c;也與 Service 業務邏輯層不同。 DAO 應該做什么&…

【Kubernetes】如何使用 kubeadm 搭建 Kubernetes 集群?還有哪些部署工具?

使用 kubeadm 搭建 Kubernetes 集群是一個比較常見的方式。kubeadm 是 Kubernetes 提供的一個命令行工具&#xff0c;它可以簡化 Kubernetes 集群的初始化和管理。下面是使用 kubeadm 搭建 Kubernetes 集群的基本步驟&#xff1a; 1. 準備工作 確保你的環境中有兩臺或更多的機…

Pycharm(十二)列表練習題

一、門和鑰匙 小X在一片大陸上探險&#xff0c;有一天他發現了一個洞穴&#xff0c;洞穴里面有n道門&#xff0c; 打開每道門都需要對應的鑰匙&#xff0c;編號為i的鑰匙能用于打開第i道門&#xff0c; 而且只有在打開了第i(i>1)道門之后&#xff0c;才能打開第i1道門&#…

在未歸一化的線性回歸模型中,特征的尺度差異可能導致模型對特征重要性的誤判

通過數學公式來更清晰地說明歸一化對模型的影響&#xff0c;以及它如何改變特征的重要性評估。 1. 未歸一化的情況 假設我們有一個線性回歸模型&#xff1a; y β 0 β 1 x 1 β 2 x 2 ? y \beta_0 \beta_1 x_1 \beta_2 x_2 \epsilon yβ0?β1?x1?β2?x2?? 其…

JS—頁面渲染:1分鐘掌握頁面渲染過程

個人博客&#xff1a;haichenyi.com。感謝關注 一. 目錄 一–目錄二–頁面渲染過程三–DOM樹和渲染樹 二. 頁面渲染過程 瀏覽器的渲染過程可以分解為以下幾個關鍵步驟 2.1 解析HTML&#xff0c;形成DOM樹 瀏覽器從上往下解析HTML文檔&#xff0c;將標簽轉成DOM節點&#…

niuhe插件, 在 go 中渲染網頁內容

思路 niuhe 插件生成的 go 代碼是基于 github.com/ma-guo/niuhe 庫進行組織管理的, niuhe 庫 是對 go gin 庫的一個封裝&#xff0c;因此要顯示網頁, 可通過給 gin.Engine 指定 HTMLRender 來實現。 實現 HTMLRender 我們使用 gitee.com/cnmade/pongo2gin 實現 1. main.go …

openEuler24.03 LTS下安裝HBase集群

前提條件 安裝好Hadoop完全分布式集群&#xff0c;可參考&#xff1a;openEuler24.03 LTS下安裝Hadoop3完全分布式 安裝好ZooKeeper集群&#xff0c;可參考&#xff1a;openEuler24.03 LTS下安裝ZooKeeper集群 HBase集群規劃 node2node3node4MasterBackup MasterRegionServ…

LVGL移植說明

https://www.cnblogs.com/FlurryHeart/p/18104596 參考&#xff0c;里面說明了裸機移植以及freeRTOS系統移植。 移植到linux https://blog.csdn.net/sunchao124/article/details/144952514

ubuntu虛擬機裁剪img文件系統

1. 定制文件系統前期準備 將rootfs.img文件準備好&#xff0c;并創建target文件夾2. 掛載文件系統 sudo mount rootfs.img target #掛載文件系統 sudo chroot target #進入chroot環境3. 內裁剪文件系統 增刪裁剪文件系統 exit #退出chroot環境 sudo umount target…

esp826601s固件燒錄方法(ch340+面包板)

esp826601s固件燒錄方法&#xff08;ch340面包板&#xff09; 硬件 stm32f10c8t6&#xff0c;esp826601s,面包板&#xff0c;ch340(usb轉ttl),st_link&#xff08;供電&#xff09; 接線 燒錄時&#xff1a; stm32f10c8t6&#xff1a;gnd->負極&#xff0c; 3.3->正極…

Servlet 點擊計數器

Servlet 點擊計數器 引言 Servlet 是 Java 企業版&#xff08;Java EE&#xff09;技術中的一種服務器端組件&#xff0c;用于處理客戶端請求并生成動態內容。本文將詳細介紹如何使用 Servlet 實現一個簡單的點擊計數器&#xff0c;幫助讀者了解 Servlet 的基本用法和原理。 …

LangChain vs. LlamaIndex:深入對比與實戰應用

目錄 引言LangChain 與 LlamaIndex 概述 什么是 LangChain&#xff1f;什么是 LlamaIndex&#xff1f;兩者的核心目標與適用場景 架構與設計理念 LangChain 的架構設計LlamaIndex 的架構設計關鍵技術差異 核心功能對比 數據連接與處理查詢與檢索機制上下文管理能力插件與擴展性…

【Java中級】10章、內部類、局部內部類、匿名內部類、成員內部類、靜態內部類的基本語法和細節講解配套例題鞏固理解【5】

?? 【內部類】干貨滿滿&#xff0c;本章內容有點難理解&#xff0c;需要明白類的實例化&#xff0c;學完本篇文章你會對內部類有個清晰的認知 &#x1f495; 內容涉及內部類的介紹、局部內部類、匿名內部類(重點)、成員內部類、靜態內部類 &#x1f308; 跟著B站一位老師學習…