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

时间:2013-07-19 10:04:10

标签: java generics type-erasure

如果我有课:

public class GenericClass<TBlah extends Number> {
    public List<String> getList() {
        return null;
    }
}

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

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

        }
    }
}

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

GenericClass<Number> a = null;

此时a.getList()会像它应该那样返回List<String>吗?

编辑:我不明白为什么getList()指定的合同应该因为我声明我的变量'a'而受到影响。 getList()始终返回List<String> TBlah 无关紧要。

1 个答案:

答案 0 :(得分:10)

因为这是泛型的工作原理。不要忘记,在声明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),那么合同将不再适用。编译器的行为就像没有类型信息一样。不要忘记编译器还需要保持与在仿制前时代创建的代码的向后兼容性