未绑定通配符与原始类型之间的差异

时间:2013-01-09 16:48:47

标签: java generics unbounded-wildcard

我正在阅读关于泛型的内容,我不了解对未绑定通配符的需求以及它与原始类型的区别。我看过this question,但仍然没有弄清楚。在Java tutorial page for unbound wildcard我得到了以下两点,我不明白第一点:

  
      
  • 如果您正在编写可以使用Object类中提供的功能实现的方法。
  •   
  • 当代码使用泛型类中不依赖于类型参数的方法时。例如,List.size()List.clear()。事实上,Class<?>经常被使用,因为Class<T>中的大部分方法都不依赖于T
  •   

有人可以用外行语言解释未绑定的通配符和原始类型之间的区别。

List<?>List<Object>的区别如何?

5 个答案:

答案 0 :(得分:34)

  

List<?>List<Object>

的区别

主要区别在于第一行编译但第二行不编译:

List<?> list = new ArrayList<String> ();
List<Object> list = new ArrayList<String> ();

但是,由于您不知道List<?>的泛型类型,您无法使用其参数化方法:

List<?> list = new ArrayList<String> ();
list.add("aString"); //does not compile - we don't know it is a List<String>
list.clear(); //this is fine, does not depend on the generic parameter type

至于与原始类型(没有泛型)的区别,下面的代码编译并运行良好:

List list = new ArrayList<String> ();
list.add("aString");
list.add(10);

答案 1 :(得分:4)

List<?>List<Object>的区别?

    List<Object> l1 = new ArrayList();
    List<?> l2 = new ArrayList();
    l1.add("Object");
    //l2.add("Object");   incorrect
    l2.add(null);

您只能将空值添加到List<?>

答案 2 :(得分:2)

我个人认为additional link from the Java tutorial on wildcards有帮助。

我在List<?>List之间看到的一个主要区别是,前者只能用于读取它的元素(除非你真的想要添加null),后者允许(未经检查)向其添加任意类型的对象,可能会产生意外的副作用。

答案 3 :(得分:1)

  

有人可以用外行语言解释未绑定的通配符和原始类型之间的区别。

未绑定的通配符类型可以维护 集合的类型不变 ,而原始类型则不能。正如Joshua Bloch在他的 Effective Java 中所说的那样,

  

您可以将任何元素放入具有原始类型的集合中,轻松破坏集合的类型不变量(如第112页的unsafeAdd方法所示);你不能把任何元素(除了null)放入Collection&lt;?&gt;。

因此,只要您将参数化类型列表分配给未绑定的通配符类型列表,就会保留 集合的类型不变

List<String> list1 = new ArrayList();
list1.add("foo");
list1.add("bar");
List<?> list2 = list1;

如果您指定其元素属于不同类型的原始类型列表,则未绑定的通配符类型将不会维护 集合的类型不变 ,因为该列表最初的类型为variant

List list1 = new ArrayList();
list1.add(1);
list1.add("foo");
List<?> list2 = list1;

答案 4 :(得分:0)

List在方法签名中很有用,可以调用从不需要type参数的方法,例如,从列表中读取或旋转它,例如。

void someMethod(List<?> list) {
  list.clear();  // I will never add anything to the list in here
}

您永远不会添加任何内容或以其他方式修改列表,因为您无法向具有此签名的方法中的null添加任何内容,因此您不会破坏类型安全性。 另一方面,您可以对原始列表执行任何操作,但我们都知道这会导致类型安全违规。

void someMethod2(List list) {
 list.add(new WeaselFurBrush());  
}
List list1 = new ArrayList<String>();
someMethod2(list1);// oops