当未指定类型参数时,为什么Java泛型原始类会擦除所有泛型对象?

Xen*_*ate 20 java generics type-erasure

如果我有课:

public class GenericClass<TBlah extends Number> {
    public List<String> getList() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试从另一个类使用该方法时:

public class OtherClass {
    public void test() {
        GenericClass a = null;
        for (String s : a.getList()) {

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么a.getList()返回a List<Object>直到我将for循环上面的行更改为:

GenericClass<Number> a = null;
Run Code Online (Sandbox Code Playgroud)

那时a.getList()返回一个List<String>它应该做的事情?

编辑:我不明白为什么指定的合同getList()应该受到如何声明我的变量'a'的影响.getList()永远都会回归List<String>,而TBlah是什么并不重要.

c.s*_*.s. 12

因为这是泛型工作的方式.不要忘记在generics之前你宣布List它是一个列表Object.你被期望放/得Object你被迫施放以获得正确类型的对象.实际上它仍然Object运行时的列表.

如果没有警告,泛型是编译器保证在编译时键入安全性的一种方法.在运行时没有List<String>.只有List.编译器会为您自动执行String s = list.get(i)强制转换,因此您可以在代码中编写而无需强制转换.

当你声明GenericClass a你正在声明一个原始类型时(你应该得到一个警告),因此编译器无法知道a.getList()应该返回什么类型.所以它使用Object.GenericClass<Number> a = null;现在声明编译器知道期望的类型a.getList()并使用所需的类型.

编辑:应该澄清的是,编译器只有在尊重签名合同时才能知道会发生什么(即情况就是如此GenericClass<Number>).如果您不尊重合同(即您使用的是原始类型extends Number),那么合同将不再适用.编译器的行为就像没有类型信息一样.不要忘记编译器还需要保持与在pre-generics时代创建的代码的向后兼容性

  • 但是getList()中List &lt;String&gt;的返回类型不受我选择TBlah的影响。那为什么重要呢? (2认同)