通配符使用准则
在学习使用泛型编程时,更令人困惑的方面之一是确定何时使用上限通配符以及何时使用下限通配符。此页面提供了一些在设计代码时要遵循的准则。
为了便于讨论,将变量视为提供以下两个功能之一是很有帮助的:
-
“Importing”变量
- “ in”变量将数据提供给代码。想象一个具有两个参数的复制方法:
copy\(src, dest\)
。src
参数提供要复制的数据,因此它是“ in”参数。
- “ in”变量将数据提供给代码。想象一个具有两个参数的复制方法:
-
“输出”变量
- “输出”变量保存要在其他地方使用的数据。在复制示例
copy\(src, dest\)
中,dest
参数接受数据,因此它是“ out”参数。
- “输出”变量保存要在其他地方使用的数据。在复制示例
当然,某些变量同时用于“Importing”和“输出”Object-准则中也解决了这种情况。
在决定是否使用通配符以及哪种类型的通配符时,可以使用“Importing”和“输出”原理。以下列表提供了要遵循的准则:
Wildcard Guidelines:
-
使用
extends
关键字,使用上限通配符定义“ in”变量。 -
使用
super
关键字使用下界通配符定义“输出”变量。 -
如果可以使用
Object
类中定义的方法访问“ in”变量,请使用无界通配符。 -
如果代码需要同时使用“ in”和“ out”变量来访问变量,则不要使用通配符。
这些准则不适用于方法的返回类型。应该避免使用通配符作为返回类型,因为它会迫使程序员使用代码来处理通配符。
可以将List\<? extends \.\.\.\>
定义的列表非正式地视为只读列表,但这不是严格的保证。假设您具有以下两个类:
class NaturalNumber {
private int i;
public NaturalNumber(int i) { this.i = i; }
// ...
}
class EvenNumber extends NaturalNumber {
public EvenNumber(int i) { super(i); }
// ...
}
考虑以下代码:
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
由于List\<EvenNumber\>
是List\<? extends NaturalNumber\>
的子类型,因此可以将le
分配给ln
。但是您不能使用ln
将自然数添加到偶数列表中。列表上的以下操作是可能的:
-
您可以添加
null
。 -
您可以调用
clear
。 -
您可以获取迭代器并调用
remove
。 -
您可以catch通配符并写入从列表中读取的元素。
从严格意义上讲,您可以看到List\<? extends NaturalNumber\>
定义的列表不是只读的,但您可能会这样想,因为您无法在列表中存储新元素或更改现有元素。