23

如果我有一堂课:

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()返回 aList<Object>直到我将 for 循环上方的行更改为:

GenericClass<Number> a = null;

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

编辑:我不明白为什么getList()我声明变量“a”的方式会影响由 指定的合同。getList()总是返回 a List<String>,不管TBlah是什么。

4

1 回答 1

15

因为这就是泛型的工作方式。不要忘记,在泛型之前,当您声明 a 时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),则合同不再适用。编译器的行为就像不存在类型信息一样。不要忘记编译器还需要保持与前泛型时代创建的代码的向后兼容性

于 2013-07-19T10:30:52.347 回答