名单<?扩展Base> VS List <Base>

use*_*454 12 java generics

List<? extends Base> list

List<Base> list
Run Code Online (Sandbox Code Playgroud)

两个声明之间有什么区别吗?

谢谢,

Oli*_*rth 13

是.

List<Base>可以包含所有来自的不同事物的混合物Base. List<? extend Base>包含同类物品(在某种意义上说,它们必须都来自某些特定的,未知的类型,而这些类型又来自Base).

换句话说,List<? extends Base>是基类List<T extends Base>.所以你可以传递List<T extends Base>给任何需要的方法List<? extends Base>.对于采用a的方法,情况也是如此List<Base>.

  • 特别是,你不能将`Base`类型的对象添加到`List <?扩展Base>`. (6认同)
  • @LouisWasserman:不仅如此,你还不能将*any*对象(除了`null`)添加到`List <?扩展Base>`,因为你不知道`?`代表什么类型. (3认同)

Nat*_*tix 6

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
Run Code Online (Sandbox Code Playgroud)

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

Object first = objects.get(1);
Object second = objects.get(2);
Object third = objects.get(3);
Run Code Online (Sandbox Code Playgroud)

他们真正运行时类仍然是Object,String而且Integer,这样你就可以将它们转换成这些类型,并与他们这样的工作,但这种强制转换可以在运行时失败了ClassCastException,如果不这样做的权利,它通常是不与这些名单的工作是个好主意时尚.

List<? extends Base> list是一个实际上没有被指定用于声明变量的声明,因为正如Daniel Pryden的评论中已经提到的那样 - 你不能add()在其中有任何对象,只有nulls.

List<? extends String> list = new ArrayList<? extends String>();
list.add("a String")); // compile error!
Run Code Online (Sandbox Code Playgroud)

但是您可以将这种有界通配符表达式用于泛型方法参数.List本身的一个例子是addAll()签名是这样的方法:

boolean addAll(Collection<? extends E> c);
Run Code Online (Sandbox Code Playgroud)

这使您可以执行以下操作:

List<String> strings = Arrays.asList("a", "b");
List<Object> objects = new ArrayList<Object>();
objects.addAll(strings);
Run Code Online (Sandbox Code Playgroud)

如果没有<? extend E>通配符它不会是可能的加StringS插入ListObjectS,因为泛型类型(不同于阵列)不是协变.这意味着a List<String> 不是 a的子类型List<Object>.但是任何String都是Object,对吧?因此,有必要使用有界通配符声明方法参数 - a List<String> 子类型List<? extends Object>.

同样,我必须指出 - 有界通配符主要指定用于泛型方法参数,而不是方法返回类型或变量声明.