避免对事件发布者进行未经检查的强制转换为 Java 中通用接口的集合

2024-03-28

我正在尝试为我正在构建的 Android 应用程序创建一个轻量级、线程安全的应用程序内发布/订阅机制。我的基本方法是跟踪列表IEventSubscriber<T>对于每个事件类型 T,然后能够通过传递类型 T 的有效负载将事件发布到订阅对象。

我使用通用方法参数来(我认为)确保订阅是以类型安全的方式创建的。因此,我非常确定,当我从订阅地图中获取订阅者列表时,当需要发布事件时,我可以将其转换为列表IEventSubscriber<T>但是,这会生成未经检查的强制转换警告。

我的问题:

  1. 未经检查的演员在这里真的安全吗?
  2. 我如何实际检查订户列表中的项目是否实现IEventSubscriber<T>?
  3. 假设(2)涉及一些令人讨厌的反思,你会在这里做什么?

代码(Java 1.6):

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;

public class EventManager {
  private ConcurrentMap<Class, CopyOnWriteArraySet<IEventSubscriber>> subscriptions = 
      new ConcurrentHashMap<Class, CopyOnWriteArraySet<IEventSubscriber>>();

  public <T> boolean subscribe(IEventSubscriber<T> subscriber,
      Class<T> eventClass) {
    CopyOnWriteArraySet<IEventSubscriber> existingSubscribers = subscriptions.
        putIfAbsent(eventClass, new CopyOnWriteArraySet<IEventSubscriber>());
    return existingSubscribers.add(subscriber);
  }

  public <T> boolean removeSubscription(IEventSubscriber<T> subscriber, 
      Class<T> eventClass) {
    CopyOnWriteArraySet<IEventSubscriber> existingSubscribers = 
        subscriptions.get(eventClass);
    return existingSubscribers == null || !existingSubscribers.remove(subscriber);
  }

  public <T> void publish(T message, Class<T> eventClass) {
    @SuppressWarnings("unchecked")
    CopyOnWriteArraySet<IEventSubscriber<T>> existingSubscribers =
        (CopyOnWriteArraySet<IEventSubscriber<T>>) subscriptions.get(eventClass);
    if (existingSubscribers != null) {
      for (IEventSubscriber<T> subscriber: existingSubscribers) {
        subscriber.trigger(message);
      }
    }
  }
}

未经检查的演员在这里真的安全吗?

相当。您的代码不会造成堆污染,因为 subcribe 的签名确保您只将正确编译时类型的 IEventSubscribers 放入映射中。它可能会在其他地方传播由不安全的未经检查的强制转换引起的堆污染,但对此您无能为力。

我如何实际检查订阅者列表中的项目是否实现了 IEventSubscriber?

通过将每个项目投射到IEventSubscriber。您的代码已在以下行中执行此操作:

for (IEventSubscriber<T> subscriber: existingSubscribers) {

If existingSubscribers包含不可分配给的对象IEventSubscriber,这一行会抛出 ClassCastException。迭代未知类型参数列表时避免警告的标准做法是显式转换每个项目:

List<?> list = ...
for (Object item : list) {
    IEventSubscriber<T> subscriber = (IEventSubscriber<T>) item;
}

该代码显式检查每个项目是否是IEventSubscriber,但无法检查它是否是IEventSubscriber<T>.

实际检查类型参数IEventSubscriber, the IEventSubscriber需要帮助你。这是由于删除,特别是考虑到声明

class MyEventSubscriber<T> implements IEventSubscriber<T> { ... }

以下表达式将始终为真:

new MyEventSubscriber<String>.getClass() == new MyEventSubscriber<Integer>.getClass()

假设(2)涉及一些令人讨厌的反思,你会在这里做什么?

我会让代码保持原样。很容易推断出强制转换是正确的,并且我认为不值得花时间重写它以在没有警告的情况下进行编译。如果您确实希望重写它,以下想法可能有用:

class SubscriberList<E> extends CopyOnWriteArrayList<E> {
    final Class<E> eventClass;

    public void trigger(Object event) {
        E event = eventClass.cast(event);
        for (IEventSubscriber<E> subscriber : this) {
            subscriber.trigger(event);
        }
    }
}

and

SubscriberList<?> subscribers = (SubscriberList<?>) subscriptions.get(eventClass);
subscribers.trigger(message);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

避免对事件发布者进行未经检查的强制转换为 Java 中通用接口的集合 的相关文章

  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • INSERT..RETURNING 在 JOOQ 中不起作用

    我有一个 MariaDB 数据库 我正在尝试在表中插入一行users 它有一个生成的id我想在插入后得到它 我见过this http www jooq org doc 3 8 manual sql building sql statemen
  • 无法展开 RemoteViews - 错误通知

    最近 我收到越来越多的用户收到 RemoteServiceException 错误的报告 我每次给出的堆栈跟踪如下 android app RemoteServiceException Bad notification posted fro
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • 多个 Maven 配置文件激活多个 Spring 配置文件

    我想在 Maven 中构建一个环境 在其中我想根据哪些 Maven 配置文件处于活动状态来累积激活多个 spring 配置文件 目前我的 pom xml 的相关部分如下所示
  • 磁模拟

    假设我在 n m 像素的 2D 表面上有 p 个节点 我希望这些节点相互吸引 使得它们相距越远吸引力就越强 但是 如果两个节点之间的距离 比如 d A B 小于某个阈值 比如 k 那么它们就会开始排斥 谁能让我开始编写一些关于如何随时间更新
  • 我可以使用 HSQLDB 进行 junit 测试克隆 mySQL 数据库吗

    我正在开发一个 spring webflow 项目 我想我可以使用 HSQLDB 而不是 mysql 进行 junit 测试吗 如何将我的 mysql 数据库克隆到 HSQLDB 如果您使用 spring 3 1 或更高版本 您可以使用 s
  • 路径中 File.separator 和斜杠之间的区别

    使用有什么区别File separator和一个正常的 在 Java 路径字符串中 与双反斜杠相反 平台独立性似乎不是原因 因为两个版本都可以在 Windows 和 Unix 下运行 public class SlashTest Test
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 从 127.0.0.1 到 2130706433,然后再返回

    使用标准 Java 库 从 IPV4 地址的点分字符串表示形式获取的最快方法是什么 127 0 0 1 到等效的整数表示 2130706433 相应地 反转所述操作的最快方法是什么 从整数开始2130706433到字符串表示形式 127 0
  • 在两个活动之间传输数据[重复]

    这个问题在这里已经有答案了 我正在尝试在两个不同的活动之间发送和接收数据 我在这个网站上看到了一些其他问题 但没有任何问题涉及保留头等舱的状态 例如 如果我想从 A 类发送一个整数 X 到 B 类 然后对整数 X 进行一些操作 然后将其发送
  • 为什么HashMap不能保证map的顺序随着时间的推移保持不变

    我在这里阅读有关 Hashmap 和 Hashtable 之间的区别 http javarevisited blogspot sg 2010 10 difference Between hashmap and html http javar
  • JRE 系统库 [WebSphere v6.1 JRE](未绑定)

    将项目导入 Eclipse 后 我的构建路径中出现以下错误 JRE System Library WebSphere v6 1 JRE unbound 谁知道怎么修它 右键单击项目 特性 gt Java 构建路径 gt 图书馆 gt JRE
  • 使用Caliper时如何指定命令行?

    我发现 Google 的微型基准测试项目 Caliper 非常有趣 但文档仍然 除了一些示例 完全不存在 我有两种不同的情况 需要影响 JVM Caliper 启动的命令行 我需要设置一些固定 最好在几个固定值之间交替 D 参数 我需要指定
  • 在 Mac 上正确运行基于 SWT 的跨平台 jar

    我一直致力于一个基于 SWT 的项目 该项目旨在部署为 Java Web Start 从而可以在多个平台上使用 到目前为止 我已经成功解决了由于 SWT 依赖的系统特定库而出现的导出问题 请参阅相关thread https stackove
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • 如何在桌面浏览器上使用 webdriver 移动网络

    我正在使用 selenium webdriver 进行 AUT 被测应用程序 的功能测试自动化 AUT 是响应式网络 我几乎完成了桌面浏览器的不同测试用例 现在 相同的测试用例也适用于移动浏览器 因为可以从移动浏览器访问 AUT 由于它是响
  • 静态变量的线程安全

    class ABC implements Runnable private static int a private static int b public void run 我有一个如上所述的 Java 类 我有这个类的多个线程 在里面r
  • 有没有办法为Java的字符集名称添加别名

    我收到一个异常 埋藏在第 3 方库中 消息如下 java io UnsupportedEncodingException BIG 5 我认为发生这种情况是因为 Java 没有定义这个名称java nio charset Charset Ch
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview

随机推荐