我目前正在编写一个简单的事件侦听器库。
这是我的所有监听器的界面:
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中的泛型或多或少只是编译时提示,可以节省强制转换并为您提供更多类型安全性。