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

San*_*mar 23 java generics unbounded-wildcard

我正在阅读关于泛型的内容,我不明白是否需要未绑定的通配符以及它与原始类型的区别.我读了这个问题,但仍然没有弄清楚.在未绑定的通配符的 Java教程页面中,我得到了以下两点,我没有理解第一点:

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

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

有List<?>什么不同List<Object>?

ass*_*ias 36

如何List<?>不同于List<Object>

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

List<?> list = new ArrayList<String> ();
List<Object> list = new ArrayList<String> ();
Run Code Online (Sandbox Code Playgroud)

但是,因为您不知道泛型类型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
Run Code Online (Sandbox Code Playgroud)

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

List list = new ArrayList<String> ();
list.add("aString");
list.add(10);
Run Code Online (Sandbox Code Playgroud)

  • 到目前为止,但是原始类型与未绑定有何不同以及为什么我们需要未绑定通配符?你能用一些很好的例子来解释一下吗? (3认同)
  • @Sandy,我认为主要的区别是使用未绑定的通配符(例如在方法签名中)表示一个承诺,即所讨论的方法知道泛型并将尊重该对象的泛型类型。对于原始类型,所有的赌注都是关闭的 - 您可以将数字添加到字符串列表中,如此处所示 - 混合通用代码和原始代码可能会导致 ClassCastExceptions 的风险。 (3认同)
  • @patrik 使用 `&lt;?&gt;` 强制编译器验证泛型安全 - 如果您使用原始类型,编译器将不会检查任何内容,并且可能会产生一些潜在的错误(尽管现在找不到示例)。由于它没有什么区别,我会坚持使用`&lt;?&gt;`。 (2认同)

Bin*_*hao 6

\n

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

\n
\n\n

未绑定的通配符类型可以保持collection\xe2\x80\x99s 类型 invariant,而原始类型则不能。正如 Joshua Bloch 在他的《Effective Java》中所说,

\n\n
\n

您可以将任何元素放入具有原始类型的集合中,很容易破坏集合\xe2\x80\x99s 类型不变性(如第 112 页上的 unsafeAdd 方法所示);您可以\xe2\x80\x99t 将任何元素(除 null 之外)放入 Collection<?> 中。

\n
\n\n

因此,只要将参数化类型列表分配给未绑定通配符类型列表,就会保持Collection\xe2\x80\x99s 类型不变量。

\n\n
List<String> list1 = new ArrayList();\nlist1.add("foo");\nlist1.add("bar");\nList<?> list2 = list1;\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您分配一个元素类型不同的原始类型列表,则未绑定通配符类型将不会维护collection\xe2\x80\x99s 类型 invariant,因为该列表最初是变体类型。

\n\n
List list1 = new ArrayList();\nlist1.add(1);\nlist1.add("foo");\nList<?> list2 = list1;\n
Run Code Online (Sandbox Code Playgroud)\n


Ant*_*huk 5

如何List<?>不同于List<Object>?

    List<Object> l1 = new ArrayList();
    List<?> l2 = new ArrayList();
    l1.add("Object");
    //l2.add("Object");   incorrect
    l2.add(null);
Run Code Online (Sandbox Code Playgroud)

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


Chr*_*ris 5

就我个人而言,我发现Java 教程中有关通配符的附加链接很有帮助。

List<?>我看到和之间的主要区别之一List是,前者只能用于读取它的元素(除非您真的想添加null),后者允许(未经检查)向其添加任意类型的对象,可能会出现意想不到的情况 -影响。