List<? extends Base>与List<Base>的区别

12
List<? extends Base> list

List<Base> list

这两个声明有什么区别吗?

谢谢。

2个回答

18

可以。

List<Base> 可以包含从 Base 派生的各种不同类型的对象。 List<? extend Base> 包含同质的对象(它们必须都派生自某个特定的未知类型,该类型又派生自 Base)。

换句话说,List<? extends Base>List<T extends Base> 的基类。因此,您可以将 List<T extends Base> 传递给任何接受 List<? extends Base> 的方法。但是对于接受 List<Base> 的方法则不是这样。


6
特别地,您不能将类型为 Base 的对象添加到 List<? extends Base> 中。 - Louis Wasserman
4
不仅如此,你无法向 List<? extends Base> 添加任何对象(除了 null),因为你不知道 ? 代表的是什么类型。 - Daniel Pryden
@LouisWasserman:简而言之,List<? extends Base> 可以传递给任何接受 List<? extends Base>、List<Base>、List<Child> 或 List<GrandChild> 的方法?那么为什么有人要使用 List<Base> 呢?我还感到困惑的是,你可以在 List<? extends Base> 和 List<Base> 上都使用 .add(...),其中 '...' 可以是任何直接或间接派生自 Base 的东西。 - user113454
1
你完全弄反了。List <? extends Base>、List <Base>、List <Child> 或 List <GrandChild> 可以传递给接受 List <? extends Base> 的方法,但不能反过来。你无法将任何东西添加到 List <? extends Base>,但可以将任何继承自 Base 的内容添加到 List <Base> 中。 - Louis Wasserman
我明白了,谢谢!我想这需要一些时间才能搞清楚这种事情! - user113454

9

List<Base> list 可以包含类型为 Base 或其任何子类型的元素。以下是一些使用JDK类的示例:

List<Object> objects = new ArrayList<Object>();
objects.add(new Object()); // adding an Object instance
objects.add("I am a String"); // a String instance is also an Object
objects.add(Integer.valueOf(5)); // an Integer instance is also an Object

但是当你检索元素时,你只能将它们分配给Object类的变量,因为Object是声明列表的类型参数。

Object first = objects.get(1);
Object second = objects.get(2);
Object third = objects.get(3);

他们真正的运行时类仍然是ObjectStringInteger,因此您可以将它们强制转换为这些类型并按照这些类型进行操作,但如果没有正确执行此类转换,则此类转换可能在运行时失败并引发ClassCastException,通常不建议以此方式处理列表。 List<? extends Base> list是一个声明,实际上并不是用于声明变量的,因为正如丹尼尔·普里登(Daniel Pryden)在评论中已经提到的那样-你不能向其中添加任何对象,只能添加null
List<? extends String> list = new ArrayList<? extends String>();
list.add("a String")); // compile error!

但是你可以在泛型方法参数中使用这样的有界通配符表达式。一个来自List本身的例子是addAll()方法,其签名如下:

boolean addAll(Collection<? extends E> c);

这使得您可以做出这样的操作:
List<String> strings = Arrays.asList("a", "b");
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);

没有 <? extend E> 通配符,就无法将这些 String 添加到 ObjectList 中,因为泛型类型(与数组不同)不是协变的。这意味着 List<String> 不是 List<Object> 的子类型。但是,任何 String 都是一个 Object,对吗?因此,有必要使用有界通配符来声明方法参数 - List<String>List<? extends Object> 的子类型。
再次强调 - 有界通配符主要用于泛型方法参数,而不是方法返回类型或变量声明。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接