Skip to content

Commit bc7098f

Browse files
authored
format code
1 parent c4f21c5 commit bc7098f

File tree

1 file changed

+134
-114
lines changed

1 file changed

+134
-114
lines changed

ch05/04_Legacy_Library_with_Generic_Client.md

+134-114
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,23 @@
99
在这种情况下,更新库以在其方法签名中使用参数化类型是有意义的,但不能更改方法体。 有三种方法可以实现这一点:对源代码进行最小限度的更改,创建存根文件或
1010
使用包装器。我们建议在仅有权访问类时有权访问源代码和使用存根时使用最少的更改 文件,我们建议不要使用包装。
1111

12-
13-
### 用最小的变化来演变一个类库
12+
#### 用最小的变化来演变一个类库
1413

1514
示例 `5-3` 显示了最小更改技术。 这里库的来源已经被编辑过,但只是为了改变方法签名,而不是方法体。 所需的确切更改以粗体显示。 当您有权访问源时,推荐使
1615
用这种技术来使库变得通用。
1716

1817
确切地说,所需的改变是:
1918

20-
- 根据需要为接口或类声明添加类型参数(对于接口 `Stack<E>` 和类 `ArrayStack<E>`
21-
22-
- 将类型参数添加到扩展或实现子句中的任何新参数化接口或类(对 `ArrayStack<E>``implements` 子句中的 `Stack<E>`),
23-
24-
- 根据需要为每个方法签名添加类型参数(用于在 `Stack<E>``ArrayStack<E>` 中进行推入和弹出操作,并在堆栈中进行反向操作)
25-
26-
- 在返回类型包含一个类型参数(对于在 `ArrayStack<E>` 中弹出,其中返回类型为 `E`)的每个返回中添加一个未经检查的强制转换 - 没有此强制转换的情况
27-
下,您将得到一个错误而不是未经检查的警告
28-
29-
- 可选择添加批注以抑制未经检查的警告(对于 `ArrayStack<E>``Stacks`
19+
- 根据需要为接口或类声明添加类型参数(对于接口 `Stack<E>` 和类 `ArrayStack<E>`
20+
21+
- 将类型参数添加到扩展或实现子句中的任何新参数化接口或类(对 `ArrayStack<E>``implements` 子句中的 `Stack<E>`),
22+
23+
- 根据需要为每个方法签名添加类型参数(用于在 `Stack<E>``ArrayStack<E>` 中进行推入和弹出操作,并在堆栈中进行反向操作)
24+
25+
- 在返回类型包含一个类型参数(对于在 `ArrayStack<E>` 中弹出,其中返回类型为 `E`)的每个返回中添加一个未经检查的强制转换 - 没有此强制转换的情况
26+
下,您将得到一个错误而不是未经检查的警告
27+
28+
- 可选择添加批注以抑制未经检查的警告(对于 `ArrayStack<E>``Stacks`
3029

3130
值得注意的是我们不需要做出一些改变。 在方法体中,我们可以保留 `Object` 的出现(参见 `ArrayStack` 中的第一行 `pop`),并且我们不需要为任何出现的raw
3231
类型添加类型参数(请参阅 `Stacks` 中的第一行)。 此外,只有当返回类型是类型参数(如 `pop` 中)时,我们才需要将转换添加到 `return` 子句中,但是当返
@@ -69,39 +68,39 @@
6968
`5-3`。 使用最小的变化来发展一个类库
7069

7170
```
72-
m/Stack.java:
73-
interface Stack<E> {
74-
public boolean empty();
75-
public void push(E elt);
76-
public E pop();
77-
}
78-
79-
m/ArrayStack.java:
80-
@SuppressWarnings("unchecked")
81-
class ArrayStack<E> implements Stack<E> {
82-
private List list;
83-
public ArrayStack() { list = new ArrayList(); }
84-
public boolean empty() { return list.size() == 0; }
85-
public void push(E elt) { list.add(elt); } // unchecked call
86-
public E pop() {
87-
Object elt = list.remove(list.size()-1);
88-
return (E)elt; // unchecked cast
71+
m/Stack.java:
72+
interface Stack<E> {
73+
public boolean empty();
74+
public void push(E elt);
75+
public E pop();
76+
}
77+
78+
m/ArrayStack.java:
79+
@SuppressWarnings("unchecked")
80+
class ArrayStack<E> implements Stack<E> {
81+
private List list;
82+
public ArrayStack() { list = new ArrayList(); }
83+
public boolean empty() { return list.size() == 0; }
84+
public void push(E elt) { list.add(elt); } // unchecked call
85+
public E pop() {
86+
Object elt = list.remove(list.size()-1);
87+
return (E)elt; // unchecked cast
88+
}
89+
public String toString() { return "stack"+list.toString(); }
90+
}
91+
92+
m/Stacks.java:
93+
@SuppressWarnings("unchecked")
94+
class Stacks {
95+
public static <T> Stack<T> reverse(Stack<T> in) {
96+
Stack out = new ArrayStack();
97+
while (!in.empty()) {
98+
Object elt = in.pop();
99+
out.push(elt); // unchecked call
89100
}
90-
public String toString() { return "stack"+list.toString(); }
91-
}
92-
93-
m/Stacks.java:
94-
@SuppressWarnings("unchecked")
95-
class Stacks {
96-
public static <T> Stack<T> reverse(Stack<T> in) {
97-
Stack out = new ArrayStack();
98-
while (!in.empty()) {
99-
Object elt = in.pop();
100-
out.push(elt); // unchecked call
101-
}
102-
return out; // unchecked conversion
103-
}
104-
}
101+
return out; // unchecked conversion
102+
}
103+
}
105104
```
106105

107106
消除(而不是抑制)编译库生成的未经检查的警告的唯一方法是更新整个库源以使用泛型。 这是完全合理的,因为除非更新整个源代码,否则编译器无法检查声明的通用
@@ -111,33 +110,41 @@
111110
`5-4`。 使用存根发展类库
112111

113112
```java
114-
s/Stack.java:
115-
interface Stack<E> {
116-
public boolean empty();
117-
public void push(E elt);
118-
public E pop();
119-
}
120-
121-
s/StubException.java:
122-
class StubException extends UnsupportedOperationException {}
123-
124-
s/ArrayStack.java:
125-
class ArrayStack<E> implements Stack<E> {
126-
public boolean empty() { throw new StubException(); }
127-
public void push(E elt) { throw new StubException(); }
128-
public E pop() { throw new StubException(); }
129-
public String toString() { throw new StubException(); }
130-
}
131-
132-
s/Stacks.java:
133-
class Stacks {
134-
public static <T> Stack<T> reverse(Stack<T> in) {
135-
throw new StubException();
136-
}
137-
}
113+
s/Stack.java:
114+
interface Stack<E> {
115+
public boolean empty();
116+
public void push(E elt);
117+
public E pop();
118+
}
119+
120+
s/StubException.java:
121+
class StubException extends UnsupportedOperationException {}
122+
123+
s/ArrayStack.java:
124+
class ArrayStack<E> implements Stack<E> {
125+
public boolean empty() {
126+
throw new StubException();
127+
}
128+
public void push(E elt) {
129+
throw new StubException();
130+
}
131+
public E pop() {
132+
throw new StubException();
133+
}
134+
public String toString() {
135+
throw new StubException();
136+
}
137+
}
138+
139+
s/Stacks.java:
140+
class Stacks {
141+
public static <T> Stack<T> reverse(Stack<T> in) {
142+
throw new StubException();
143+
}
144+
}
138145
```
139146

140-
### 使用存根演化库
147+
#### 使用存根演化库
141148

142149
示例 `5-4` 中显示了存根技术。 在这里,我们编写了具有通用签名但不包含 `body` 的存根。我们针对通用签名编译通用客户端,但针对遗留类文件运行代码。 这种
143150
技术适用于源未发布或其他人负责维护源的情况。
@@ -149,14 +156,14 @@
149156
件(比如在目录 `l` 中)进行这种操作。
150157

151158
```java
152-
% javac -classpath s g/Client.java
153-
% java -ea -classpath l g/Client
159+
% javac -classpath s g/Client.java
160+
% java -ea -classpath l g/Client
154161
```
155162

156163
再说一遍,这是有效的,因为为传统文件和通用文件生成的类文件基本相同,除了关于类型的辅助信息。 特别是,客户端编译的通用签名与传统签名(除了关于类型参数
157164
的辅助信息)相匹配,因此代码可以成功运行并提供与以前相同的答案。
158165

159-
### 使用包装进化库
166+
#### 使用包装进化库
160167

161168
`5-5` 给出了这个包装技术。 在这里,我们保留原有的源文件和类文件不变,并提供通过代理访问遗留类的通用包装类。我们主要介绍这种技术,主要是为了警告您
162169
不要使用它 - 通常最好使用最少的更改或存根。
@@ -188,48 +195,61 @@
188195
`5-5`。 使用包装器发展一个库
189196

190197
```java
191-
//不要这样做---不推荐使用包装类
192-
l/Stack.java, l/Stacks.java, l/ArrayStack.java:
193-
// As in Example 5.1
194-
w/GenericStack.java:
195-
interface GenericStack<E> {
196-
public Stack unwrap();
197-
public boolean empty();
198-
public void push(E elt);
199-
public E pop();
200-
}
201-
w/GenericStackWrapper.java:
202-
@SuppressWarnings("unchecked")
203-
class GenericStackWrapper<E> implements GenericStack<E> {
204-
private Stack stack;
205-
public GenericStackWrapper(Stack stack) { this.stack = stack; }
206-
public Stack unwrap() { return stack; }
207-
public boolean empty() { return stack.empty(); }
208-
public void push(E elt) { stack.push(elt); }
209-
public E pop() { return (E)stack.pop(); } // unchecked cast
210-
public String toString() { return stack.toString(); }
211-
}
212-
w/GenericStacks.java:
213-
class GenericStacks {
214-
public static <T> GenericStack<T> reverse(GenericStack<T> in) {
215-
Stack rawIn = in.unwrap();
216-
Stack rawOut = Stacks.reverse(rawIn);
217-
return new GenericStackWrapper<T>(rawOut);
218-
}
219-
}
220-
w/Client.java:
221-
class Client {
222-
public static void main(String[] args) {
223-
GenericStack<Integer> stack = new GenericStackWrapper<Integer>(new ArrayStack());
224-
for (int i = 0; i<4; i++) stack.push(i);
225-
assert stack.toString().equals("stack[0, 1, 2, 3]");
226-
int top = stack.pop();
227-
assert top == 3 && stack.toString().equals("stack[0, 1, 2]");
228-
GenericStack<Integer> reverse = GenericStacks.reverse(stack);
229-
assert stack.empty();
230-
assert reverse.toString().equals("stack[2, 1, 0]");
231-
}
232-
}
198+
//不要这样做---不推荐使用包装类
199+
l/Stack.java, l/Stacks.java, l/ArrayStack.java:
200+
// As in Example 5.1
201+
w/GenericStack.java:
202+
interface GenericStack<E> {
203+
public Stack unwrap();
204+
public boolean empty();
205+
public void push(E elt);
206+
public E pop();
207+
}
208+
w/GenericStackWrapper.java:
209+
@SuppressWarnings("unchecked")
210+
class GenericStackWrapper<E> implements GenericStack<E> {
211+
private Stack stack;
212+
public GenericStackWrapper(Stack stack) {
213+
this.stack = stack;
214+
}
215+
public Stack unwrap() {
216+
return stack;
217+
}
218+
public boolean empty() {
219+
return stack.empty();
220+
}
221+
public void push(E elt) {
222+
stack.push(elt);
223+
}
224+
public E pop() {
225+
return (E)stack.pop();
226+
} // unchecked cast
227+
public String toString() {
228+
return stack.toString();
229+
}
230+
}
231+
w/GenericStacks.java:
232+
class GenericStacks {
233+
public static <T> GenericStack<T> reverse(GenericStack<T> in) {
234+
Stack rawIn = in.unwrap();
235+
Stack rawOut = Stacks.reverse(rawIn);
236+
return new GenericStackWrapper<T>(rawOut);
237+
}
238+
}
239+
w/Client.java:
240+
class Client {
241+
public static void main(String[] args) {
242+
GenericStack<Integer> stack = new GenericStackWrapper<Integer>(new ArrayStack());
243+
for (int i = 0; i<4; i++)
244+
stack.push(i);
245+
assert stack.toString().equals("stack[0, 1, 2, 3]");
246+
int top = stack.pop();
247+
assert top == 3 && stack.toString().equals("stack[0, 1, 2]");
248+
GenericStack<Integer> reverse = GenericStacks.reverse(stack);
249+
assert stack.empty();
250+
assert reverse.toString().equals("stack[2, 1, 0]");
251+
}
252+
}
233253
```
234254

235255
包装也呈现更深和更微妙的问题。 如果代码使用对象标识,则可能会出现问题,因为遗留对象和包装对象是不同的。 此外,复杂的结构将需要多层包装纸。 想象一下,

0 commit comments

Comments
 (0)