Guidelines for Wildcard Use

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

为了便于讨论,将变量视为提供两个功能之一是很有帮助的:

An "In" Variable

in(输入)变量将数据提供给代码。想象一个具有两个参数的复制函数:copy(src,dest)src参数提供要复制的数据,因此它是in参数。

An "Out" Variable

out(输出)变量保存要在其他地方使用的数据。在复制函数copy(src,dest)中,dest参数接受数据,因此它是out参数。

当然有些变量是输入也是输出,这种场景也会讨论到。

在决定是否使用通配符以及使用哪种类型的通配符时,可以使用“输入”和“输出”原则。

Wildcard Guidelines:

  • in变量使用通过extends关键字定义的上界通配符

  • out变量使用通过super关键字定义的下界通配符

  • 如果可以使用Object类中定义的方法访问in变量,请使用无界通配符。

  • 如果代码需要同时使用inout变量来访问变量,则不要使用通配符。

这些准则不适用于函数的返回类型。应该避免使用通配符作为返回类型,因为这样会迫使程序员使用代码来处理通配符。

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

  • 获取iterator并且调用remove

  • 捕获通配并写入从列表中读取的元素

我们可以看到由List <?extended NaturalNumber>定义的列表,从严格意义上讲不是只读的,但是我们可以认为它是只读,因为我们无法插入新元素或更改列表中的现有元素。

Last updated