[英]Java generic/wildcard type mismatch
I'm trying to build a Java event emitter, which would have a list of callbacks (implementing Consumer interface) mapped with an event name. 我正在尝试构建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;
}
}
I get this compile error: 我收到此编译错误:
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
but the captured type is clearly a subtype of , so it should work (but I understand I'm missing something). 但捕获的类型显然是的子类型,因此它应该可以工作(但我知道我遗漏了一些内容)。
The use should be something like this (where OpenEvent and CloseEvent extend EventObject of course): 用法应该是这样的(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());
I suppose it's possible to do this type-safe, since I can specify the type of the consumer's object via lambda function. 我想可以进行这种类型安全的操作,因为我可以通过lambda函数指定使用者对象的类型。 But how?
但是如何?
That happens because listener
is of type: Consumer<? extends EventObject>
这是因为
listener
的类型是: Consumer<? extends EventObject>
Consumer<? extends EventObject>
(so, it's a Consumer
of some specific, but unknown type that extends EventObject
), but you want it to accept an event of type E
. Consumer<? extends EventObject>
所以,这是一个Consumer
,扩展一些特定的,但不知道类型EventObject
),但你希望它接受类型的事件E
。 The compiler cannot check if the unknown type indicated by the wildcard is equal to the type E
. 编译器无法检查该通配符表示未知类型等于类型
E
。
Why are you using wildcards at all? 为什么要使用通配符? It would be better to get rid of them, and do something like this:
最好摆脱它们,并执行以下操作:
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;
}
}
Note: A wildcard type with a ? extends EventObject
注意:带
? extends EventObject
通配符类型? extends EventObject
? extends EventObject
does not mean you can pass any object to it that extends EventObject
; ? extends EventObject
并不意味着你可以传递任何对象将其延伸EventObject
; it specifies one specific, but unknown type that extends EventObject
. 它指定一个扩展特定,但未知类型
EventObject
。 Because what the exact type is, is unknown, this limits what you can do with it. 由于确切的类型是什么,还是个未知数,这限制了你可以用它做什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.