我遇到了关于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;)
我怀疑为什么会发生这种情况 - 它可能与泛型和类型擦除有关 - 但我无法解决它。
我的问题:
注意:关于泛型和/或类型擦除的帖子很多;但是,我无法找到这个问题的答案。如果您认为另一个答案是合适的,请链接到它。
答案 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
}
}
}