java为什么列表<String>不能作为列表<Object>接受?
考虑下面的方法^ {< CD1>},它接受^ {< CD2>}作为参数。
private void doSomething(List<Object> list) {
// do something
}
现在考虑下面的代码片段,它试图调用^ {< CD3>},在这里我试图通过^ {< CD4> }到^ {CD3>}/P>
List<Object> objectList;
List<String> stringList;
doSomething(stringList); // compilation error incompatible types
doSomething(objectList); // works fine
甚至下面的代码也会抛出编译错误
objectList = stringList; // compilation error incompatible types
我的问题是为什么List<String>
不能传递给接受List<Object>
的方法
# 1 楼答案
来自泛型Java教程:
让我们测试一下您对泛型的理解。以下代码段合法吗
第一行当然是合法的。问题中比较棘手的部分是第2行。这归结为一个问题:字符串列表是对象列表吗。大多数人本能地回答:“当然!”
好的,看下面几行:
在这里,我们将ls和lo化名为。通过别名lo访问ls(字符串列表),我们可以在其中插入任意对象。因此,ls不再仅仅是一个字符串,当我们试图从中得到一些东西时,我们会得到一个粗鲁的惊喜
Java编译器当然会阻止这种情况发生。第2行将导致编译时错误强>
资料来源:Generics and Subtyping
# 2 楼答案
这些限制的原因与差异因素有关
以下面的代码为例:
展开示例,您可以尝试执行以下操作:
希望很明显,如果编译器允许编译这段代码(它不允许),那么这段代码将中断—当试图将
Object
转换为String
时,列表中的第二项将出现ClassCastException
要能够传递通用集合类型,您需要执行以下操作:
同样,编译器正在监视您,如果您将
System.out
替换为objects.add(new Object())
,编译器将不允许这样做,因为objects
可能被创建为List<String>
有关差异的更多背景信息,请参阅维基百科文章Covariance and contravariance
# 3 楼答案
如果有效,则可能会将错误类型的对象放入列表:
# 4 楼答案
因为
String
扩展Object
,而List<String>
不扩展List<Object>
更新:
通常,如果
Foo
是Bar
的子类型(子类或子接口),并且G
是某种泛型类型声明,那么G<Foo>
不是G<Bar>
的子类型这是因为集合确实发生了变化。在您的情况下,如果
List<String>
是List<Object>
的子类型,则在使用其超类型引用列表时,可以向其添加除String
以外的类型,如下所示:Java编译器必须防止这些情况
更多关于thisJava教程页面的详细说明
# 5 楼答案
有时可以预期
List<Object>
将是List<String>
的超类型,因为Object
是String
的超类型这种期望源于这样一个事实,即数组存在这样一种类型关系:
Object[]
是String[]
的超类型,因为Object
是String
的超类型。(这种类型的关系称为协方差。)组件类型的超级子类型关系扩展到相应的数组类型中
泛型类型的实例化不存在这样的类型关系。(参数化类型不是协变的。)强>
有关详细信息,请查看here
# 6 楼答案
Java中的这个泛型问题可能会让任何不太熟悉泛型的人感到困惑,因为乍一看,字符串就是对象,所以
List<String>
可以在需要List<Object>
的地方使用,但事实并非如此。这将导致编译错误如果你更进一步,这是有意义的,因为
List<Object>
可以存储任何东西,包括String
、Integer
等等,但是List<String>
只能存储Strings
还可以看看:Why not inherit from List<T>?