繁体   English   中英

Java通用/通配符类型不匹配

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM