我目前正在编写一个简单的事件侦听器库。

这是我的所有监听器的界面:

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;
            }
}


在这种情况下,编译器仅生成两个警告,但我已阅读here,该技术非常非常糟糕!


我使用此代码

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禁用该警告。

编辑:很难摆脱未经检查的对话警告。它们只是意味着编译器无法执行该强制转换。以下语句是正确的,无用的,并且稍后会在某些地方破坏您的代码:

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


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

10-08 11:46
查看更多