Java通用/通配符类型不匹配 [英] Java generic/wildcard type mismatch

查看:148
本文介绍了Java通用/通配符类型不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建一个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< ;?扩展EventObject>>>听众;

public Emitter()
{
this.listeners = new HashMap< String,PriorityQueue< Consumer<扩展EventObject>>>();

$ b $ public 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);

返回这个;
}

public< E extends EventObject>发射器发射(E事件)
{
String eventName = event.getClass()。getName();

(Consumer< ;? extends EventObject> listener:this.listeners.get(eventName)){
listener.accept(event);
}

返回此;
}
}

我得到这个编译错误:

  Emitter.java:31:错误:不兼容的类型:E无法转换为CAP#1 
listener.accept(event);
^
其中E是类型变量:
E扩展在方法< E>中发出的EventObject发送(E)
其中CAP#1是一个新的类型变量:
CAP#1扩展了EventObject的捕获?扩展EventObject

但捕获的类型显然是一个子类型,所以它应该工作(但我理解我'
$ b

使用应该是这样的(当然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 的类型为:消费< ;?扩展EventObject> (所以,它是一个 Consumer 的某些特定但未知的类型,它扩展了 EventObject ),但您希望它接受 E 类型的事件。编译器无法检查通配符指示的未知类型是否等于类型 E



为什么你使用通配符?

  public class Emitter< E extends EventObject>这是最好的解决方法。 
{
protected HashMap< String,PriorityQueue< Consumer< E>>>听众;
$ b $ public Emitter()
{
this.listeners = new HashMap< String,PriorityQueue< Consumer< E>>>();


公共Emitter on(String eventName,Consumer< E>侦听器)
{
if(!this.listeners.containsKey(eventName)){
this.listeners.put(eventName,new PriorityQueue< Consumer< E>>());
}

this.listeners.get(eventName).add(listener);

返回这个;
}

public Emitter emit(E event)
{
String eventName = event.getClass()。getName(); (Consumer< E> listener:this.listeners.get(eventName)){
listener.accept(event);


}

返回此;


注意:通配符类型包含?扩展EventObject 意味着你可以传递任何对象给它以扩展 EventObject ;它指定了一个扩展 EventObject 的特定但未知的类型。因为确切类型是什么,是未知的,这限制了你可以用它做什么。


I'm trying to build a Java event emitter, which would have a list of callbacks (implementing Consumer interface) mapped with an event name.

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):

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. But how?

解决方案

That happens because listener is of type: 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. The compiler cannot check if the unknown type indicated by the wildcard is equal to the type 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 does not mean you can pass any object to it that extends EventObject; it specifies one specific, but unknown type that extends EventObject. Because what the exact type is, is unknown, this limits what you can do with it.

这篇关于Java通用/通配符类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆