Class Generics打破了完全独立的方法

The*_*eLQ 3 java generics

当我使用类Generics Today时,我发现了一个奇怪的问题:设置一些打破了一个完全独立的方法.

这是一个说明问题的小示例类.这段代码工作得很好

public class Sandbox {
    public interface ListenerManagerTest {
        public Set<Listener> getListeners();
    }

    public void setListenerManager(ListenerManagerTest listenerManager) {
        for (Listener curListener : listenerManager.getListeners())
            return;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,只要我使用类Generics,该getListeners()方法将返回Set<Object>而不是Set<Listener>

public class Sandbox {
    public interface ListenerManagerTest<E extends Object> {
        public Set<Listener> getListeners();
    }

    public void setListenerManager(ListenerManagerTest listenerManager) {
        for (Listener curListener : listenerManager.getListeners()) //Expected Listener, not Object
            return;
    }
}
Run Code Online (Sandbox Code Playgroud)

什么会导致这个错误?在##javaFreenode上信道说,这是因为编译时的糖果和我使用的是原始类型.但是原始类类型如何打破类中的所有泛型?以前怎么样?

axt*_*avt 6

使用原始类型(即ListenerManagerTest代替ListenerManagerTest<...>)禁用其所有成员的泛型,因此将public Set<Listener> getListeners()其视为public Set getListeners(),因此您无法在没有额外强制转换的情况下迭代它.

使用参数化类型而不是原始类型(如果需要,使用通配符):

public void setListenerManager(ListenerManagerTest<?> listenerManager) { ... }
Run Code Online (Sandbox Code Playgroud)

这是为了向后兼容.想象一下,您需要创建遗留的非泛型类泛型.在这种情况下,对泛型不了解的遗留代码仍然可以将该类用作原始类型,并且不需要更改.但是,该遗留代码也不知道该类的成员的泛型类型,因此默认情况下将它们视为原始类型是有意义的.

下面是一个遗留代码的示例,在ListManagerTest没有此规则的情况下将泛型添加到类后会被破坏:

public void addListenersToTest(ListenerManagerTest listenerManager, Set listeners) {
    listenerManager.getListeners().addAll(listeners);
}
Run Code Online (Sandbox Code Playgroud)

一般来说,引入原始类型的概念是为了向后兼容,并且不建议不需要使用原始类型.这就是原始类型具有这些奇怪的兼容性相关功能的原因.