编译器如何推断java泛型中的类型

时间:2016-04-21 18:19:13

标签: java generics

我的通用方法看起来像这样。

public static <T> T addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return element;
}

当我打电话

String stringElement = "stringElement";
List<Object> objectList = new ArrayList<Object>();
Object theElement = addAndReturn(stringElement, objectList); 

它将类型推断为对象。

当我打电话

Object objectElement = new Object();
List<String> stringList = new ArrayList<String>();
Object theElement = addAndReturn(objectElement, stringList);

编译器报告错误。

这背后的规则是什么?

3 个答案:

答案 0 :(得分:4)

在第一种情况下,您将List<Object>传递给Collection<T>,因此T必须是Object类型。 String stringElementObject的子类,所以这是允许的。

在第二种情况下,您将List<String>传递给Collection<T>,因此T只能是String。由于Object objectElement不是String类型,因此不允许这样做。

您无法向Object添加List<String>这似乎是合理的。

答案 1 :(得分:1)

泛型可能很难掌握,我建议你仔细阅读。

在您的示例中,您有一个T类型,可以是任何一种类型。这种类型是“通用的”,因为它符合放入它的类型。因此,当您将ArrayList<String>作为Collection<T>参数传递时,T在该实例中变为String。因此,方法的返回类型变为String

答案 2 :(得分:1)

泛型工作在类型推理的原则上。编译器检查泛型类中的类型。一旦确定了类型,编译器就会执行编译时类型检查,以确保传递的所有类型都是正确的。泛型在运行时也有类型擦除,但这是另一回事,我们可以跳过它进行讨论。

在您的问题上应用此原则: 在第一种情况下,您正在创建一个String类型的对象,可以很容易地将其添加到Object类型的ArrayList中,因为String是Object的子类。

对于第二个例子,你现在正好相反。您正在尝试将String类对象保存在String类的引用中,这是不允许的。

因此,如果您注意到规则与非通用代码的规则完全相同。