使用通配符和类型化泛型会生成"is not applicable for the arguments"错误



我目前正在编写一个简单的事件侦听器库。
下面是我的监听器接口:

public interface Listener<T> {
    // Event is a very simple type which holds a variable T data.
    public boolean run(Event<T> e);
}

我的类Listenable在HashMap中记录了所有Listener:

protected HashMap<String, ArrayList<Listener<?>>> listeners;

我在这里使用通配符,因为我希望我的Listenable实例有多个事件类型。

问题部分现在出现在我的Listenable::dispatchEvent()方法中:

public boolean dispatchEvent(Event<?> evt) {
        ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
        if (evtListeners == null) {
            return true;
        }
        for (Listener<?> lst : evtListeners) {
        //           vvv--- error
            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
        }

        return true;
}

错误信息显示:

类型中的run(Event)方法侦听器不适用于参数(事件)

我找到了一个"解决方案"(在让编译器隐藏错误的意义上):

for (Listener lst : evtListeners) {
            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
}

在这种情况下,编译器只生成两个警告,但是我在这里读到这种技术非常非常差!


我用这段代码让它工作

public <T> boolean dispatchEvent(Event<T> evt) {
        ArrayList<Listener<?>> evtListeners = listeners.get(evt.getType());
        if (evtListeners == null) {
            return true;
        }
        for (int i = 0; i < evtListeners.size(); i++) {
            @SuppressWarnings("unchecked")
            Listener<T> lst = (Listener<T>) evtListeners.get(i);
            if (!lst.run(evt) || evt.shouldStopPropagation()) {
                return false;
            }
        }
        return true;
}

但我怀疑这是干净的代码,不是吗?我假设库的用户不会为相同的事件类型(evt.getType())混合类型。

我将感谢任何建议!

您应该将方法的签名更改为

public <T> boolean dispatchEvent(Event<T> evt)
并使用T作为类型:
for (Listener<T> lst : (ArrayList<Listener<T>>) evtListeners) {

注意,这通常给出一个"未检查的对话"警告,你可以禁用@SuppressWarnings("unchecked") iirc。

Edit:很难摆脱未检查的对话警告。它们仅仅意味着编译器不能强制强制转换。下面的语句是正确的,无用的,并且会在稍后的某个地方破坏您的代码:

ArrayList<Thread> al1 = new ArrayList<Thread>();
al1.add(new Thread());
ArrayList<Exception> al2 = (ArrayList<Exception>) al1;
Java中的

泛型或多或少只是一个编译时提示,它可以节省强制转换并为您提供更多的类型安全性。

最新更新