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