List<? extends Base> list
List<Base> list
这两个声明有什么区别吗?
谢谢。
可以。
List<Base>
可以包含从 Base
派生的各种不同类型的对象。 List<? extend Base>
包含同质的对象(它们必须都派生自某个特定的未知类型,该类型又派生自 Base
)。
换句话说,List<? extends Base>
是 List<T extends Base>
的基类。因此,您可以将 List<T extends Base>
传递给任何接受 List<? extends Base>
的方法。但是对于接受 List<Base>
的方法则不是这样。
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);
Object
、String
和Integer
,因此您可以将它们强制转换为这些类型并按照这些类型进行操作,但如果没有正确执行此类转换,则此类转换可能在运行时失败并引发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
添加到 Object
的 List
中,因为泛型类型(与数组不同)不是协变的。这意味着 List<String>
不是 List<Object>
的子类型。但是,任何 String
都是一个 Object
,对吗?因此,有必要使用有界通配符来声明方法参数 - List<String>
是 List<? extends Object>
的子类型。
Base
的对象添加到List<? extends Base>
中。 - Louis WassermanList<? extends Base>
添加任何对象(除了null
),因为你不知道?
代表的是什么类型。 - Daniel Pryden