我遇到了有关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);

}


另一个班级

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 类型的方法eventOccurred(SomeEvent )不适用于参数(SomeEvent )


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

我的问题:


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


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

最佳答案

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

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

您不能将其转换为SomeEvent<?>-实际上,除SomeEvent<?>之外,您无法将任何内容转换为null?的意思是“我不知道这个类型的参数是什么。”

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

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>。显然,这是不允许的-因此,这是不允许的。

07-24 21:06