The Java™ Tutorials — Generics :Guidelines for Wildcard Use 通配符使用指南
原文地址:https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
关键点
- “输入”和“输出”变量的定义
- 输入:负责添加数据到代码中,类比一个入口
- 输出:负责接收输入的数据,并将其传到需要的地方,类比一个出口
- 通配符准则:
- 一个“输入”变量是通过有上限通配符定义的,它使用了extends关键字
- 一个“输出”变量是通过有下限通配符定义的,它使用了super关键字
- 当“输入”变量可通过Object类中的方法获取时,那就使用一个无限制通配符
- 当代码需要获取一个兼具“输入”和“输出”功能的变量时,就不要使用通配符了
- List<? extends XXX>不能插入新的元素(但可以插入null),也不能对已经有元素进行更改,但是可以调用clear()方法删除所有元素,可以将其视之为一种广义上的只读
- 译者注:用Eclipse看了一下它的方法,所操纵的元素对象都是null类型的。
全文翻译
One of the more confusing aspects when learning to program with generics is determining when to use an upper bounded wildcard and when to use a lower bounded wildcard. This page provides some guidelines to follow when designing your code.
在学习泛型编程时,一个最容易引起疑惑的点是何时使用有上限通配符,而何时使用有下限通配符。本文提供了一些在设计代码时可以遵循的方针。
For purposes of this discussion, it is helpful to think of variables as providing one of two functions:
为了更好的理解我们所讨论的内容,思考一下那些提供了下面两种功能之一的变量是很有好处的:
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.
一个“输入变量”负责把数据添加到代码中。想象一个复制方法,它具有两个参数:copy(src,dest)。这个src参数提供了将要被拷贝的数据对象,因此它就是那个“输入”变量。
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.
一个“输出”变量持有了为别处使用的数据。在上面的那个copy(src,dest)
案例中,这个dest变量负责接收数据,因此也就是所谓的“输出”变量。
Of course, some variables are used both for “in” and “out” purposes — this scenario is also addressed in the guidelines.
当然,一些变量兼具“输入”和“输出”两种功能——这样的场景我们在本章节中也会遇到。
You can use the “in” and “out” principle when deciding whether to use a wildcard and what type of wildcard is appropriate. The following list provides the guidelines to follow:
在决定是否使用通配符,以及适用的通配符类型时,你就可以使用“输入”和“输出”准则来帮助你做决定。下面就列出了需要遵循的准则:
Wildcard Guidelines 通配符准则
- An “in” variable is defined with an upper bounded wildcard, using the extends keyword.
- An “out” variable is defined with a lower bounded wildcard, using the super keyword.
- In the case where the “in” variable can be accessed using methods defined in the Object class, use an unbounded wildcard.
- In the case where the code needs to access the variable as both an “in” and an “out” variable, do not use a wildcard.
- 一个“输入”变量是通过有上限通配符定义的,它使用了extends关键字
- 一个“输出”变量是通过有下限通配符定义的,它使用了super关键字
- 当“输入”变量可通过Object类中的方法获取时,那就使用一个无限制通配符
- 当代码需要获取一个兼具“输入”和“输出”功能的变量时,就不要使用通配符了
These guidelines do not apply to a method’s return type. Using a wildcard as a return type should be avoided because it forces programmers using the code to deal with wildcards.
这些准则不适用于方法的返回类型。应该避免使用通配符作为一个返回类型,因为这会逼迫编程者在代码中使用通配符进行处理。
A list defined by List<? extends …> can be informally thought of as read-only, but that is not a strict guarantee. Suppose you have the following two classes:
一个被List<? extends ...>
定义的列表可被简单的想象为一种只读列表,但是这并非是严格保证的。假设你有下面的两个类:
class NaturalNumber {
private int i;
public NaturalNumber(int i) { this.i = i; }
// ...
}
class EvenNumber extends NaturalNumber {
public EvenNumber(int i) { super(i); }
// ...
}
Consider the following code:
看下下面的代码:
List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35)); // compile-time error
Because
List<EvenNumber>
is a subtype ofList<? extends NaturalNumber>
, you can assign le to ln. But you cannot use ln to add a natural number to a list of even numbers. The following operations on the list are possible:
- You can add null.
- You can invoke clear.
- You can get the iterator and invoke remove.
- You can capture the wildcard and write elements that you’ve read from the list.
因为List<EvenNumber>
是List<? extends NaturalNumber>
的子类型,你就可以将le赋值给ln。但是你不能使用ln去把一个自然数添加到偶数列表中去。而下面的列表操作是有效的:
- 可以插入一个null
- 可以调用clear()方法
- 可以获取一个遍历器,并调用remove()方法
- 可以对通配符进行匹配,并写入已经从list读出的元素
You can see that the list defined by List<? extends NaturalNumber> is not read-only in the strictest sense of the word, but you might think of it that way because you cannot store a new element or change an existing element in the list.
你可以看到由List<? extends NaturalNumber>定义的列表并不是严格意义上的只读,但你可以这么想,因为你不能在list中存储一个新的元素或者改变一个原有的元素。