[英]Java generic/wildcard type mismatch
我正在尝试构建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函数指定使用者对象的类型。 但是如何?
这是因为listener
的类型是: Consumer<? extends EventObject>
Consumer<? extends EventObject>
所以,这是一个Consumer
,扩展一些特定的,但不知道类型EventObject
),但你希望它接受类型的事件E
。 编译器无法检查该通配符表示未知类型等于类型E
。
为什么要使用通配符? 最好摆脱它们,并执行以下操作:
public class Emitter<E extends EventObject>
{
protected HashMap<String, PriorityQueue<Consumer<E>>> listeners;
public Emitter()
{
this.listeners = new HashMap<String, PriorityQueue<Consumer<E>>>();
}
public Emitter on(String eventName, Consumer<E> listener)
{
if (!this.listeners.containsKey(eventName)) {
this.listeners.put(eventName, new PriorityQueue<Consumer<E>>());
}
this.listeners.get(eventName).add(listener);
return this;
}
public Emitter emit(E event)
{
String eventName = event.getClass().getName();
for (Consumer<E> listener : this.listeners.get(eventName)) {
listener.accept(event);
}
return this;
}
}
注意:带? extends EventObject
通配符类型? extends EventObject
? extends EventObject
并不意味着你可以传递任何对象将其延伸EventObject
; 它指定一个扩展特定,但未知类型EventObject
。 由于确切的类型是什么,还是个未知数,这限制了你可以用它做什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.