我的通用方法看起来像这样。
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);
编译器报告错误。
这背后的规则是什么?
答案 0 :(得分:4)
在第一种情况下,您将List<Object>
传递给Collection<T>
,因此T
必须是Object
类型。 String stringElement
是Object
的子类,所以这是允许的。
在第二种情况下,您将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类的引用中,这是不允许的。
因此,如果您注意到规则与非通用代码的规则完全相同。