我正在尝试构建一个Java事件发射器,其中包含一个与事件名称映射的回调列表(实现Consumer接口)。
我收到了这个编译错误:
import java.util.HashMap;
import java.util.PriorityQueue;
import java.util.function.Consumer;
import java.util.EventObject;
public class Emitter
{
protected HashMap<String, PriorityQueue<Consumer<? extends EventObject>>> listeners;
public Emitter()
{
this.listeners = new HashMap<String, PriorityQueue<Consumer<? extends EventObject>>>();
}
public Emitter on(String eventName, Consumer<? extends EventObject> listener)
{
if (!this.listeners.containsKey(eventName)) {
this.listeners.put(eventName, new PriorityQueue<Consumer<? extends EventObject>>());
}
this.listeners.get(eventName).add(listener);
return this;
}
public <E extends EventObject> Emitter emit(E event)
{
String eventName = event.getClass().getName();
for (Consumer<? extends EventObject> listener : this.listeners.get(eventName)) {
listener.accept(event);
}
return this;
}
}
我收到了这个编译错误:
Emitter.java:31: error: incompatible types: E cannot be converted to CAP#1
listener.accept(event);
^
where E is a type-variable:
E extends EventObject declared in method <E>emit(E)
where CAP#1 is a fresh type-variable:
CAP#1 extends EventObject from capture of ? extends EventObject
但是被捕获的类型明显是子类型,所以它应该可以工作(但我知道我漏掉了什么)。
使用方法应该像这样(其中OpenEvent和CloseEvent当然扩展自EventObject):
Emitter em = new Emitter();
em.on("open", (OpenEvent e) -> e.doOpen());
em.on("close", (CloseEvent e) -> e.doClose());
em.emit(new OpenEvent());
em.emit(new CloseEvent());
我认为可能可以通过使用 lambda 函数来指定消费者对象的类型,以实现类型安全。但是如何做到呢?
Emitter
就不会是一个异构容器了,对吧? - Rohit JainEmitter
就不会是一个异构容器,它确实会把Emitter
与单个的EventObject
子类型绑定。我认为这在完全类型安全的方式下是不可能的,除非进行强制转换。 - JesperEmitter
中删除类型参数E
,使用Consumer<EventObject>
代替Consumer<E>
,然后在需要使用EventObject
的地方,使用instanceof
检查实际类型并将其转换为该实际类型。 - JesperMyObject
本身是泛型时,我无法执行listeners.add(new MyObject())
。 - Mark Jeronimus