Java泛型在消息订阅发布中将事件种类与载荷类型编译期绑定,通过标记接口IEvent和泛型子类(如AddConfigEvent<T>)实现类型安全;订阅时锁定具体泛型类型,发布时强类型构造,运行时按Class<?>分组分发,兼顾安全与灵活性。

Java 中泛型在通用消息订阅发布中规范事件数据类型,核心是让“事件种类”和“载荷类型”在编译期就绑定为一个不可分割的整体,而不是靠字符串、Object 或运行时判断来区分。
用空接口统一事件契约,泛型子类承载具体数据
所有事件实现同一个无方法的标记接口(如 IEvent),不定义业务字段;真正携带数据的是它的泛型实现类:
-
AddConfigEvent<T>:T 是配置的具体类型(如
WordPressConfig) -
SaveDocumentEvent<T>:T 是文档实体(如
MarkdownDoc) - 每个
AddConfigEvent<WordPressConfig>和AddConfigEvent<CnblogsConfig>在 Java 类型系统里是两个完全不同的类,互不兼容
订阅时锁定泛型类型,避免转型与反射
订阅方法签名直接接收泛型事件类型,例如:
subscribe(Consumer<AddConfigEvent<WordPressConfig>> handler)- 注册时传入 lambda:
e -> sendNotification(e.getData().getSiteUrl()) - IDE 可自动补全
e.getData()的字段,编译器能校验是否调用了WordPressConfig特有方法 - 运行时无需
if (e instanceof ...)或Class.forName(...),也不依赖字符串匹配事件名
发布端强类型构造,数据原样传递
发布者创建事件对象时,必须明确指定泛型参数:
立即学习“Java免费学习笔记(深入)”;
eventBus.publish(new AddConfigEvent<CnblogsConfig>() {{ setData(config); }});- 接收方拿到的就是
CnblogsConfig实例,不是Object,不需要强制转换 - 不同 T 的同一事件模板,在字节码层面就是不同类,天然隔离,不会误触发
内部存储按 Class<?> 分组,兼顾类型安全与运行时分发
事件总线底层可用 Map<Class<?>, List<Consumer<?>>> 管理监听器,但关键操作需配合类型擦除补偿:
- 注册时:用
handler.getClass().getGenericInterfaces()或传入Class<T>显式标记事件类型 - 发布时:
event.getClass()获取真实类型,查表后做一次(Consumer<T>) consumer强转(仅此处,且安全) - 比全反射或字符串路由更轻量,比纯泛型单主题更灵活,适合中大型系统


















