未绑定通配符与原始类型之间的差异
我正在阅读关于generics的内容,我不明白是否需要未绑定的通配符以及它与原始类型的区别。 我读了这个问题,但仍然没有弄清楚。 在未绑定的通配符的Java教程页面中,我得到了以下两点,我没有理解第一点:
- 如果您正在编写可以使用
Object
类中提供的function实现的方法。- 当代码使用generics类中不依赖于类型参数的方法时。 例如,
List.size()
或List.clear()
。 实际上,经常使用Class
因为Class
大多数方法都不依赖于T
有人可以用外行语言解释未绑定的通配符和原始类型之间的区别。
List
与List
有何不同?
List>
与List
不同之处
主要区别在于第一行编译但第二行不编译:
List> list = new ArrayList (); List
但是,因为您不知道List>
的generics类型是什么,所以您不能使用其参数化方法:
List> list = new ArrayList (); list.add("aString"); //does not compile - we don't know it is a List list.clear(); //this is fine, does not depend on the generic parameter type
至于与原始类型(没有generics)的区别,下面的代码编译并运行正常:
List list = new ArrayList (); list.add("aString"); list.add(10);
List>
与List
不同之处是什么?
List
您只能将空值添加到List>
就个人而言,我从通配符的Java教程中发现这个额外的链接很有用。
我在List>
和List
之间看到的主要区别之一是前者只能用于读取它的元素(除非你真的想要添加null
),后者允许(未经检查)添加任意类型的对象它可能带来意想不到的副作用。
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(); someMethod2(list1);// oops
有人可以用外行语言解释未绑定的通配符和原始类型之间的区别。
未绑定的通配符类型可以维护集合的类型不变 ,而原始类型不能。 正如Joshua Bloch在他的Effective Java中所说,
您可以将任何元素放入具有原始类型的集合中,轻松破坏集合的类型不变量(如第112页的unsafeAdd方法所示); 你不能把任何元素(除了null)放入Collection <?>中。
因此,只要将参数化类型列表分配给未绑定通配符类型列表,就会保留集合的类型不变量 。
List 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;