Skip to content

Commit 12699b5

Browse files
authored
Merge pull request lingcoder#240 from thinker1990/generics
泛型 - 简单泛型小节翻译完成
2 parents 977d29d + 41aa629 commit 12699b5

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

docs/book/20-Generics.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,105 @@ public class TupleTest {
259259

260260
在上面的程序中,`new` 表达式有些啰嗦。本章稍后会介绍,如何利用 *泛型方法* 简化它们。
261261

262+
### 一个堆栈类
263+
264+
接下来我们看一个稍微复杂一点的例子:堆栈。在[集合](./12-Collections.md)一章中,我们用 `LinkedList` 实现了 `onjava.Stack` 类。在那个例子中,`LinkedList` 本身已经具备了创建堆栈所需的方法。`Stack` 是通过两个泛型类 `Stack<T>``LinkedList<T>` 的组合来创建。我们可以看出,泛型只不过是一种类型罢了(稍后我们会看到一些例外的情况)。
265+
266+
这次我们不用 `LinkedList` 来实现自己的内部链式存储机制。
267+
268+
```java
269+
// generics/LinkedStack.java
270+
// 用链式结构实现的堆栈
271+
272+
public class LinkedStack<T> {
273+
private static class Node<U> {
274+
U item;
275+
Node<U> next;
276+
277+
Node() { item = null; next = null; }
278+
Node(U item, Node<U> next) {
279+
this.item = item;
280+
this.next = next;
281+
}
282+
283+
boolean end() {
284+
return item == null && next == null;
285+
}
286+
}
287+
288+
private Node<T> top = new Node<>(); // 栈顶
289+
290+
public void push(T item) {
291+
top = new Node<>(item, top);
292+
}
293+
294+
public T pop() {
295+
T result = top.item;
296+
if (!top.end()) {
297+
top = top.next;
298+
}
299+
return result;
300+
}
301+
302+
public static void main(String[] args) {
303+
LinkedStack<String> lss = new LinkedStack<>();
304+
for (String s : "Phasers on stun!".split(" ")) {
305+
lss.push(s);
306+
}
307+
String s;
308+
while ((s = lss.pop()) != null) {
309+
System.out.println(s);
310+
}
311+
}
312+
}
313+
```
314+
315+
输出结果:
316+
317+
```java
318+
stun!
319+
on
320+
Phasers
321+
```
322+
323+
内部类 `Node` 也是一个泛型,它拥有自己的类型参数。
324+
325+
这个例子使用了一个 *末端标识* (end sentinel) 来判断栈何时为空。这个末端标识是在构造 `LinkedStack` 时创建的。然后,每次调用 `push()` 就会创建一个 `Node<T>` 对象,并将其链接到前一个 `Node<T>` 对象。当你调用 `pop()` 方法时,总是返回 `top.item`,然后丢弃当前 `top` 所指向的 `Node<T>`,并将 `top` 指向下一个 `Node<T>`,除非到达末端标识,这时就不能再移动 `top` 了。如果已经到达末端,程序还继续调用 `pop()` 方法,它只能得到 `null`,说明栈已经空了。
326+
327+
### RandomList
328+
329+
作为容器的另一个例子,假设我们需要一个持有特定类型对象的列表,每次调用它的 `select()` 方法时都随机返回一个元素。如果希望这种列表可以适用于各种类型,就需要使用泛型:
330+
331+
```java
332+
// generics/RandomList.java
333+
import java.util.*;
334+
import java.util.stream.*;
335+
336+
public class RandomList<T> extends ArrayList<T> {
337+
private Random rand = new Random(47);
338+
339+
public T select() {
340+
return get(rand.nextInt(size()));
341+
}
342+
343+
public static void main(String[] args) {
344+
RandomList<String> rs = new RandomList<>();
345+
Array.stream("The quick brown fox jumped over the lazy brown dog".split(" ")).forEach(rs::add);
346+
IntStream.range(0, 11).forEach(i ->
347+
System.out.print(rs.select() + " "));
348+
);
349+
}
350+
}
351+
```
352+
353+
输出结果:
354+
355+
```java
356+
brown over fox quick quick dog brown The brown lazy brown
357+
```
358+
359+
`RandomList` 继承了 `ArrayList` 的所有方法。本例中只添加了 `select()` 这个方法。
360+
262361
<!-- Generic Interfaces -->
263362

264363
## 泛型接口

0 commit comments

Comments
 (0)