Java编译器忽略类型安全性

Far*_*mor 7 java oop generics types type-safety

public class POJO<T> {

    private List<Integer> integer = new ArrayList<Integer>();

    public POJO() {
        integer.add(1);
        integer.add(2);
    }

    public List<Integer> getInteger() {
        return integer;
    }

    public static void main(String[] args) {
        POJO pojo = new POJO();
        List<String> integer = pojo.getInteger(); // No compile error?
        System.out.println(integer); // prints [1, 2]
    }
}
Run Code Online (Sandbox Code Playgroud)

如何编译以下行:

List<String> integer = pojo.getInteger();
Run Code Online (Sandbox Code Playgroud)

提供getInteger()的类型如下

public List<Integer> getInteger()
Run Code Online (Sandbox Code Playgroud)

Pet*_*rey 7

由于pojo未被声明为通用

POJO pojo = new POJO();
Run Code Online (Sandbox Code Playgroud)

编译器假定您在预通用代码中使用它.即在编写代码后添加泛型的地方.所以,当你这样做

List<String> integer = pojo.getInteger(); 
Run Code Online (Sandbox Code Playgroud)

你收到警告而不是错误.

即如果类型是非泛型的,则关闭所有通用检查,而不仅仅是那些与您没有给出的类型相关的检查.我相信这是为了最大限度地向后兼容.

为了比较.

Map mapOfInteger = new Map(); // no generics
Set<String> entries = map.entrySet(); // gives a warning, not an error.
Run Code Online (Sandbox Code Playgroud)

在这个例子中,如果不是通用的,你可能会期望Set<Entry<K, V>>变成Set<Entry>泛型,但编译器会回退到将类视为非泛型Set.


ass*_*ias 7

我在JLS 4.8中找到了一个参考资料来支持@PeterLawrey所说的内容:

的类型构造函数(§8.8),实例方法的(8.4节,第9.4节),或者非静态字段(§8.3),其不从其超类或超接口继承的原类型C的M是原始类型对应在对应于C的通用声明中擦除其类型

因此,原始POJO对象的所有实例方法都将被删除,包括那些不引用其类型T的方法POJO<T>,这意味着(JLS 4.6):

如果[...]方法的签名被删除,方法的类型参数(第8.4.4节)和方法的返回类型(第8.4.5节)也会被擦除.