我正在阅读关于泛型的内容,我不了解对未绑定通配符的需求以及它与原始类型的区别。我看过this question,但仍然没有弄清楚。在Java tutorial page for unbound wildcard我得到了以下两点,我不明白第一点:
- 如果您正在编写可以使用
Object
类中提供的功能实现的方法。- 当代码使用泛型类中不依赖于类型参数的方法时。例如,
List.size()
或List.clear()
。事实上,Class<?>
经常被使用,因为Class<T>
中的大部分方法都不依赖于T
。
有人可以用外行语言解释未绑定的通配符和原始类型之间的区别。
List<?>
与List<Object>
的区别如何?
答案 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