方法不适用于Java中有关泛型或类型擦除的参数

时间:2014-07-03 11:23:05

标签: java generics type-erasure

我遇到了关于Java泛型的问题。

我试图建立一个监听SomeEventListener的监听器(称为SomeEvent)。那些事件的结果具有特定的类型;我希望通过方法getResult()检索该结果,其返回类型为T。触发该事件时,将调用eventOccurred(SomeEvent<T>)方法。

SomeEvent类:

public class SomeEvent<T> {

    private T result;

    public SomeEvent(T result) {
        this.result = result;
    }

    public T getResult() {
        return this.result;
    }
}

SomeEventListener类:

public interface SomeEventListener<T> {

    void eventOccurred(SomeEvent<T> event);

}

AnotherClass类

public class AnotherClass {

    ArrayList<SomeEventListener<?>> listeners = new ArrayList<SomeEventListener<?>>();

    <T> void fireSomethingOccursEvent(SomeEvent<T> event) {
        for (SomeEventListener<?> listener : this.listeners) {
            listener.eventOccurred(event); // MARKED LINE
        }
    }
}

但是,嘿,Eclipse在MARKED LINE上给出错误:

  

SomeEventListener&lt; capture#2-of?&gt;类型的方法eventOccurred(SomeEvent&lt; capture#2-of?&gt;)不适用于参数(SomeEvent&lt; T&gt;)

我怀疑为什么会发生这种情况 - 它可能与泛型和类型擦除有关 - 但我无法解决它。

我的问题:

  • 为什么上述代码无效?
  • 如何修复代码?

注意:关于泛型和/或类型擦除的帖子很多;但是,我无法找到这个问题的答案。如果您认为另一个答案是合适的,请链接到它。

2 个答案:

答案 0 :(得分:2)

您有一个SomeEventListener<?>,其方法为void eventOccurred(SomeEvent<?> event)(将?替换为T)。

对于某些完全不相关的SomeEvent<T>,您还有一个T

您无法将其转换为SomeEvent<?> - 事实上,除了SomeEvent<?>之外,您无法将任何内容转换为null?表示&#34;我不知道这种类型的论点是什么。&#34;

例如,如果允许您的代码,此代码将编译,但传递错误的类型:

AnotherClass ac = new AnotherClass();

ac.listeners.add(new SomeEventListener<Integer>() {
    void eventOccurred(SomeEvent<Integer> event) {
        System.out.println(event.intValue());
    }
});

SomeEvent<String> event = new SomeEvent<String>("Hello");
ac.fireSomethingOccursEvent(event);

现在fireSomethingOccursEvent会占用SomeEvent<String>并将其传递给SomeEventListener<Integer>。这显然不应该被允许 - 因此,它是不允许的。

答案 1 :(得分:0)

您可以制作整个AnotherClass通用并使用wildcards

public class AnotherClass<T> {

    ArrayList<SomeEventListener<? super T>> listeners = new ArrayList<>();
    //use diamond-type since java 1.7

    void fireSomethingOccursEvent(SomeEvent<? extends T> event) {
        for (SomeEventListener<? super T> listener : this.listeners) {
            listener.eventOccurred(event); // should be fine
        }
    }
}