Java 为什么 List<String> 不能作为 List<Object> 接受?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22144671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:54:00  来源:igfitidea点击:

Why List<String> is not acceptable as List<Object>?

javagenericscasting

提问by user3374518

Consider below method doSomething(List<Object>)which accepts List<Object>as parameter.

考虑下面doSomething(List<Object>)接受List<Object>作为参数的方法。

private void doSomething(List<Object> list) {
    // do something
}

Now consider below code snippet which tries to call doSomething()where I try to pass List<String>to doSomething()

现在考虑下面的代码片段,它试图调用doSomething()我尝试传递List<String>的位置doSomething()

List<Object> objectList;
List<String> stringList;

doSomething(stringList); // compilation error incompatible types
doSomething(objectList); // works fine 

Even below code throws compilation error

即使在下面的代码中也会抛出编译错误

objectList = stringList;  // compilation error incompatible types

My question is why List<String>can not be passed to a method which accepts List<Object>?

我的问题是为什么List<String>不能传递给接受的方法List<Object>

采纳答案by Shishir Kumar

This generic question in Java may look confusing to any one who is not very familiar with Generics as in first glance it looks like String is object so List<String>can be used where List<Object>is required but this is not true. It will result in compilation error.

Java 中的这个通用问题可能会让任何不太熟悉泛型的人感到困惑,因为乍一看它看起来 String 是对象,因此List<String>可以在List<Object>需要的地方使用,但事实并非如此。会导致编译错误。

It does make sense if you go one step further because List<Object>can store anythingincluding String, Integeretc but List<String>can only store Strings.

这有一定道理,如果你走一步,因为List<Object>能够存储任何东西,包括StringInteger等,但List<String>只能存储Strings

Also have a look at: Why not inherit from List<T>?

也看看:为什么不从 List<T> 继承?

回答by Ahmad Y. Saleh

Because while Stringextends Object, List<String>does not extend List<Object>

因为 whileString扩展ObjectList<String>不扩展List<Object>

Update:
In general, if Foois a subtype (subclass or subinterface) of Bar, and Gis some generic type declaration, it is not the case that G<Foo>is a subtype of G<Bar>.

更新:
通常, ifFoo是 的子类型(子类或子接口)Bar,并且G是某种泛型类型声明,则不是 的G<Foo>子类型G<Bar>

This is because collections do change. In your case, If List<String>was a subtype of List<Object>, then types other than Stringcan be added to it when the list is referenced using its supertype, as follows:

这是因为集合确实会发生变化。在您的情况下, IfList<String>是 的子类型List<Object>,那么String当使用其超类型引用列表时,可以将其他类型添加到其中,如下所示:

List<String> stringList = new ArrayList<String>;
List<Object> objectList = stringList;// this does compile only if List<String> where subtypes of List<Object>
objectList.add(new Object());
String s = stringList.get(0);// attempt to assign an Object to a String :O

and the Java compiler has to prevent these cases.

并且 Java 编译器必须防止这些情况。

More elaboration on thisJava Tutorial page.

Java 教程页面上有更多详细说明。

回答by Marco13

You could put an object of a wrong type into the list IFthis worked:

如果这有效,您可以将错误类型的对象放入列表中:

private void doSomething(List<Object> list) {
    list.add(new Integer(123)); // Should be fine, it's an object
}

List<String> stringList = new ArrayList<String>();
doSomething(stringList); // If this worked....
String s = stringList.get(0); // ... you'd receive a ClassCastException here

回答by rsakhale

If you are not sure what datatype it will take in you can make use of Generics in Java as follows

如果您不确定它将采用什么数据类型,您可以按如下方式使用 Java 中的泛型

public static void doSomething(List<?> data) {

}

public static void main(String [] args) {
    List<Object> objectList = new ArrayList<Object>();
    List<String> stringList = new ArrayList<String>();
    doSomething(objectList);
    doSomething(stringList);
}

But while using the data, you will be required to specify proper data type as a Type Cast

但是在使用数据时,您将需要指定正确的数据类型作为类型转换

回答by Abimaran Kugathasan

It is sometimes expected that a List<Object>would be a supertype of a List<String>, because Objectis a supertype of String.

有时预期 aList<Object>将是 a 的超类型List<String>,因为Object是 的超类型String

This expectation stems from the fact that such a type relationship exists for arrays:

这种期望源于这样一个事实,即数组存在这样的类型关系:

Object[]is a supertype of String[], because Objectis a supertype of String. (This type relationship is known as covariance .)

Object[]是 的超类型String[],因为Object是 的超类型String。(这种类型的关系称为协方差。)

The super-subtype-relationship of the component types extends into the corresponding array types.

组件类型的超子类型关系扩展到相应的数组类型。

No such a type relationship exists for instantiations of generic types. (Parameterized types are not covariant.)

泛型类型的实例化不存在这样的类型关系。(参数化类型不是协变的。)

Check herefor more details

查看此处了解更多详情

回答by Ankit Lamba

From Java Tutorials of Generics:

来自 Java 泛型教程:

Let's test your understanding of generics. Is the following code snippet legal?

让我们测试您对泛型的理解。下面的代码片段合法吗?

List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2 

Line 1 is certainly legal. The trickier part of the question is line 2. This boils down to the question: is a List of String a List of Object. Most people instinctively answer, "Sure!"

第 1 行当然是合法的。问题的棘手部分是第 2 行。这归结为问题:字符串列表是对象列表。大多数人本能地回答:“当然!”

Well, take a look at the next few lines:

好吧,看看接下来的几行:

lo.add(new Object()); // 3
String s = ls.get(0); // 4: Attempts to assign an Object to a String!

Here we've aliased ls and lo. Accessing ls, a list of String, through the alias lo, we can insert arbitrary objects into it. As a result ls does not hold just Strings anymore, and when we try and get something out of it, we get a rude surprise.

这里我们给 ls 和 lo 取了别名。通过别名lo访问ls这个String列表,我们可以在其中插入任意对象。结果 ls 不再只保存字符串,当我们尝试从中得到一些东西时,我们会得到一个粗鲁的惊喜。

The Java compiler will prevent this from happening of course. Line 2 will cause a compile time error.

Java 编译器当然会阻止这种情况发生。第 2 行将导致编译时错误。

Source : Generics and Subtyping

来源:泛型和子类型

回答by Nick Holt

The reason for these limitations have to do with variance considerations.

这些限制的原因与差异考虑有关。

Take the following code:

取以下代码:

public void doSomething(List<Object> objects)
{
  objects.add(new Object());
}

Expanding your example, you could try to do the following:

扩展您的示例,您可以尝试执行以下操作:

List<String> strings = new ArrayList<String>();
string.add("S1");

doSomething(strings);

for (String s : strings)
{
  System.out.println(s.length);
}

Hopefully it's obvious why this would break if the compiler allowed this code to be compiled (which it doesn't) - a ClassCastExceptionwould occur for the second item in the list when trying to cast the Objectto a String.

希望这是显而易见的,为什么如果编译器允许这段代码进行编译(这事实并非如此),这将打破-一个ClassCastException试图施放时会在列表中出现的第二项ObjectString

To be able to pass generalized collection types, you need to do this:

为了能够传递通用集合类型,您需要执行以下操作:

public void doSomething(List<?> objects)
{
  for (Object obj : objects)
  {
    System.out.println(obj.toString);
  }
}

Again, the compiler is watching your back and were you to replace the System.outwith objects.add(new Object())the compiler wouldn't allow this because objectscould have been created as List<String>.

同样,编译器都在注视着你的背部和为您更换System.outobjects.add(new Object())编译器不会允许这一点,因为objects可以为已创建List<String>

For more background on Variance see the Wikipedia artical Covariance and contravariance

有关方差的更多背景信息,请参阅维基百科 artical Covariance and contravariance