如何在没有&"unchecked&"的情况下转换为(已知)泛型类型警告? [英] How cast to (known) generic type without "unchecked" warning?

查看:52
本文介绍了如何在没有&"unchecked&"的情况下转换为(已知)泛型类型警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这两个界面;

public interface Event {
    default void dispatch() {
        EventBus.getInstance().dispatch(this);
    }
}

public interface EventListener<T extends Event> {
    void handle(T event);
}

如果我正确理解Java中的泛型,实际上是在告诉第二个接口的继承者放置

If I understand generics in Java correctly, I'm practically telling the inheritor of the second interface to put th

然后我想出了下一段代码,可以在其中注册侦听器,可以引发事件,并且已注册的侦听器将处理所有引发的事件.

Then I came up with the next this piece of code, where listeners can be registered, events can be thrown and registered listeners will handle any thrown event.

public class EventBus {

    /**
     * The singleton EventBus instance.
     */
    private static EventBus instance;

    /**
     * The map of event types and their listeners.
     */
    private final Map<Class<? extends Event>, Set<EventListener<? extends Event>>> listeners = new ConcurrentHashMap<>();

    /**
     * Create a new EventBus instance.
     */
    private EventBus() {

    }

    /**
     * Retrieve the singleton bus instance.
     *
     * @return The event bus instance.
     */
    public static EventBus getInstance() {
        if (instance == null) {
            instance = new EventBus();
        }

        return instance;
    }

    /**
     * Register a new event listener, that listens to the given event type.
     *
     * @param <T>
     * @param type     The type of event that the given listener should react on.
     * @param listener The listener that we want to register.
     */
    public <T extends Event> void registerListener(Class<T> type, EventListener<T> listener) {
        Set<EventListener<? extends Event>> eventListeners = getOrCreateListeners(type);

        eventListeners.add(listener);
    }

    /**
     * Retrieve a set of listeners, either by retrieving an existing list or by creating a new one.
     *
     * @param eventClass The type of event for which to retrieve listeners.
     *
     * @return A set of event listeners that listen for the given event.
     */
    private Set<EventListener<? extends Event>> getOrCreateListeners(Class<? extends Event> eventClass) {
        Set<EventListener<? extends Event>> eventSubscribers = listeners.get(eventClass);

        if (eventSubscribers == null) {
            eventSubscribers = new CopyOnWriteArraySet<>();
            listeners.put(eventClass, eventSubscribers);
        }

        return eventSubscribers;
    }

    /**
     * Dispatch the given event to all registered listeners associated with that type.
     *
     * @param <T>
     * @param event The event that is to be dispatched.
     */
    public <T extends Event> void dispatch(T event) {
        listeners.keySet().stream()
                .filter(type -> type.isAssignableFrom(event.getClass()))
                .flatMap(type -> listeners.get(type).stream())
                .forEach(listener -> {
                    try {
                        ((EventListener<T>) listener).handle(event); //  <-- This is where the compiler warns me...
                    } catch (Exception e) {
                        Thread.currentThread().getUncaughtExceptionHandler().uncaughtException(Thread.currentThread(), e);
                    }
                });
    }
}

发出警告的行位于底部附近:(((EventListener< T>)listener).handle(event);

The line throwing a warning is near the bottom: ((EventListener<T>) listener).handle(event);

事件监听器的代码大致基于

The code for the event listener is loosely based on this piece of code. Sadly, that piece doesn't make use of generics whatsoever. When I add separate interfaces for event and listener, a lot of rawtype and unchecked warnings appear in the code. I started turning a few of the methods and the listeners Map into generic ones. I have been fiddling around with question marks, Ts and much more trying to figure this out. I've already learned a lot about generics from coding this but I can't seem to figure this one out.

我认为可以通过以下两种方式找到答案:a)将监听器映射成泛型(以某种方式?):我想告诉编译器 EventListener<中的事件类型?扩展Event> 的类型就是 Class< ;?扩展Event> 描述.或者,b)在发出警告的行上创建安全"强制转换.

I think that the answer can be found in either a) turning the listeners Map generic (somehow?): I want to tell the compiler that the type of event in the EventListener<? extends Event> is of the type that that Class<? extends Event> describes. Or, b) creating a "safe" cast on the line that gives a warning.

我通过这样做(以及更多尝试)尝试了第一种选择:

I tried the first option by doing this (and some more attempts):

/**
 * The map of event types and their listeners.
 */
private final Map<Class<T extends Event>, Set<EventListener<T>>> listeners = new ConcurrentHashMap<>();

但是运气不好,编译器会告诉您.

But without much luck, as the compiler will tell you.

我还尝试通过添加以下if语句来尝试第二种选择(这里也进行了几次尝试):

I also attempted the second option by adding the following if-statement (a few more attempts were made here as well):

if (listener instanceof EventListener<T>) {
    ((EventListener<T>) listener).handle(event); //  <-- This is where the compiler warns me...
}

这也不起作用,因为T的类型将在运行时删除...

This won't work either, as the type of T will be erased at runtime...

也许我已经接近了,但是只是没有使用正确的语法.也许我什至无法将正确的信息传递给编译器或将其保存在运行时中.也许我什至不在正确的轨道上...

到目前为止,我已经浏览了 this 这一个,可惜运气不佳.

So far I've browsed issues like this, this and this one, sadly without much luck.

推荐答案

不幸的是,知道 .filter(type-> type.isAssignableFrom(event.getClass()))过滤掉不合适的类型,编译器不知道(也不知道),因此发出警告.

Unfortunately while you know that .filter(type -> type.isAssignableFrom(event.getClass())) filters out unsuitable types, the compiler doesn't (and can't) know it, hence the warning.

您的侦听器映射具有通用参数,只是这些通用参数不允许您保持完整的(编译时)类型安全.通配符可以确保这一点.您知道(在编译时)该映射包含某些事件的侦听器作为值,但是一旦将侦听器放入其中,就无法再将其取出,而又不会失去编译时类型的安全性.

Your map of listeners has generic parameters that just won't allow you to keep full (compile time) type safety. The wildcards make sure of that. You know (at compile-time) that the map contains listeners for some events as values, but as soon as you put a listener in there, you can't take it out anymore without losing compile-time type safety.

Map<Class<? extends Event>, Set<EventListener<? extends Event>>> listeners

那么您有什么选择?好了,您知道检查事件类型后 是运行时类型安全的,因此您可能只想在方法上标记 @SuppressWarnings 批注并继续.毕竟,这只是警告,以确保您知道自己在做什么.

So what are your options? Well, you know that it is runtime typesafe after you check the event type, so you might just want to tag a @SuppressWarnings annotation on the method and move on. After all, it's just a warning to make sure you know what you're doing.

这篇关于如何在没有&amp;"unchecked&amp;"的情况下转换为(已知)泛型类型警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆