在下面的代码段中,添加" Hulooo"列表生成编译器错误,因为String不扩展String。 但是,类型化字符串的ArrayList工作。但是对对象的ArrayList进行类型转换并不起作用。
有人可以解释为什么会这样吗? 什么适用于String(在此上下文中)不适用于Object?
public static void takeList(List<? extends String> list)
{
list.add("Hulloo");//ERROR
list=new ArrayList<String>();
list=new ArrayList<Object>();//ERROR
}
答案 0 :(得分:4)
问号?
是一个所谓的外卡操作员。 List<? extends String>
表示:任何类型List<T>
T
为String
或子类型为String
。 String
是一个最终类,因此没有String
的子类型,但编译器不会看这个。因此,编译器假定列表可能是String
的某个子类型的列表,并且不可能将String
添加到这样的列表中。
让我们使用非最终类A
来模拟您的示例,该类具有子类B
:
class A {
// empty
}
class B extends A {
void f();
}
现在考虑相当于你的方法:
public static void takeList(List<? extends A> list) {
list.add(new A());
}
由于以下原因,这将无法编译。假设您按如下方式调用此方法:
List<B> myList = new ArrayList<>(); // line 1
takeList(myList); // line 2
B element = myList.get(0); // line 3
B.f(); // line 4
由于B
是A
的子类,因此第2行中的函数调用是合法的。但是方法takeList
会将A
添加到列表中,而不是B
。然后,B
的列表包含一个不是B
的元素,第3行和第4行分解。
类型系统用于防止输入错误,因此如果有一种情况可以将错误类型的对象添加到列表中,则类型系统必须禁止它。