通配符使用指南

原文: https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html

学习使用泛型编程时,更令人困惑的一个方面是确定何时使用上限有界通配符以及何时使用下限有界通配符。此页面提供了设计代码时要遵循的一些准则。

出于本讨论的目的,将变量视为提供两个函数之一是有帮助的:

An “In” Variable

An “in” variable serves up data to the code. Imagine a copy method with two arguments: copy(src, dest). The src argument provides the data to be copied, so it is the “in” parameter.

An “Out” Variable

An “out” variable holds data for use elsewhere. In the copy example, copy(src, dest), the dest argument accepts data, so it is the “out” parameter.

当然,一些变量既用于“进入”又用于“出”目的 - 这种情况也在指南中得到解决。

在决定是否使用通配符以及适合使用哪种类型的通配符时,可以使用“in”和“out”原则。以下列表提供了遵循的准则:


Wildcard Guidelines:

  • 使用extends关键字,使用上限通配符定义“in”变量。
  • 使用super关键字,使用下限通配符定义“out”变量。
  • 如果可以使用Object类中定义的方法访问“in”变量,请使用无界通配符。
  • 在代码需要作为“in”和“out”变量访问变量的情况下,不要使用通配符。

这些指南不适用于方法的返回类型。应该避免使用通配符作为返回类型,因为它强制程序员使用代码来处理通配符。

List&lt ;?定义的列表扩展...>可以被非正式地认为是只读的,但这不是严格的保证。假设您有以下两个类:

  1. class NaturalNumber {
  2. private int i;
  3. public NaturalNumber(int i) { this.i = i; }
  4. // ...
  5. }
  6. class EvenNumber extends NaturalNumber {
  7. public EvenNumber(int i) { super(i); }
  8. // ...
  9. }

请考虑以下代码:

  1. List<EvenNumber> le = new ArrayList<>();
  2. List<? extends NaturalNumber> ln = le;
  3. ln.add(new NaturalNumber(35)); // compile-time error

因为List&lt; EvenNumber>List&lt;?的子类型扩展 NaturalNumber> ,你可以将le分配给ln 。但你不能使用ln将自然数添加到偶数列表中。列表中的以下操作是可能的:

  • 您可以添加null
  • 你可以调用清除
  • 你可以得到迭代器并调用删除
  • 您可以捕获通配符并写入从列表中读取的元素。

您可以看到List&lt;?定义的列表扩展 NaturalNumber>在严格意义上不是只读的,但您可能会这样想,因为您无法存储新元素或更改列表中的现有元素。