名单<! - ?扩展Base - > VS List <base />

时间:2012-02-28 19:33:03

标签: java generics

List<? extends Base> list

List<Base> list

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

谢谢,

2 个答案:

答案 0 :(得分:12)

List<Base>可以包含所有来自Base的不同内容的混合。 List<? extend Base>包含同类项(从某种意义上说,它们必须全部来自某些特定的,未知类型,而这些类型又来自Base)。

换句话说,List<? extends Base>List<T extends Base>的基类。因此,您可以将List<T extends Base>传递给任何需要List<? extends Base>的方法。采用List<Base>的方法也是如此。

答案 1 :(得分: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

但是当你检索元素时,你只能将它们分配给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的评论中已经提到的那样 - 你不能add()其中的任何对象,只有null s。< / p>

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添加到List Object中,因为泛型类型(与数组不同)不是协变。这意味着List<String> 不是 List<Object>的子类型。但是任何String都是Object,对吗?因此,有必要使用有界通配符声明方法参数 - List<String> 是<{1}}的子类型。

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