|
11 | 11 |
|
12 | 12 | 我们已经在复制方法的签名中看到了这个原理:
|
13 | 13 |
|
14 |
| - ```java |
15 |
| - public static <T> void copy(List<? super T> dest, List<? extends T> src) |
16 |
| - ``` |
| 14 | +```java |
| 15 | + public static <T> void copy(List<? super T> dest, List<? extends T> src) |
| 16 | +``` |
17 | 17 |
|
18 | 18 | 该方法从源 `src` 中获取值,因此使用扩展通配符声明值,并将值放入目标 `dst` 中,因此使用超级通配符声明值。
|
19 | 19 |
|
20 | 20 | 无论何时使用迭代器,都会从结构中获取值,因此请使用扩展通配符。 这是一个需要一个数字集合的方法,每个转换为一个双精度求和:
|
21 | 21 |
|
22 |
| - ```java |
23 |
| - public static double sum(Collection<? extends Number> nums) { |
24 |
| - double s = 0.0; |
25 |
| - for (Number num : nums){ |
26 |
| - s += num.doubleValue(); |
27 |
| - } |
28 |
| - return s; |
| 22 | +```java |
| 23 | + public static double sum(Collection<? extends Number> nums) { |
| 24 | + double s = 0.0; |
| 25 | + for (Number num : nums){ |
| 26 | + s += num.doubleValue(); |
29 | 27 | }
|
30 |
| - ``` |
| 28 | + return s; |
| 29 | + } |
| 30 | +``` |
31 | 31 |
|
32 | 32 | 由于这个使用 `extends`,所有以下的调用是合法的:
|
33 | 33 |
|
34 |
| - ```java |
35 |
| - List<Integer> ints = Arrays.asList(1,2,3); |
36 |
| - assert sum(ints) == 6.0; |
37 |
| - List<Double> doubles = Arrays.asList(2.78,3.14); |
38 |
| - assert sum(doubles) == 5.92; |
39 |
| - List<Number> nums = Arrays.<Number>asList(1,2,2.78,3.14); |
40 |
| - assert sum(nums) == 8.92; |
41 |
| - ``` |
| 34 | +```java |
| 35 | + List<Integer> ints = Arrays.asList(1,2,3); |
| 36 | + assert sum(ints) == 6.0; |
| 37 | + List<Double> doubles = Arrays.asList(2.78,3.14); |
| 38 | + assert sum(doubles) == 5.92; |
| 39 | + List<Number> nums = Arrays.<Number>asList(1,2,2.78,3.14); |
| 40 | + assert sum(nums) == 8.92; |
| 41 | +``` |
42 | 42 |
|
43 | 43 | 如果不使用 `extends`,前两个调用将不合法
|
44 | 44 |
|
45 | 45 | 每当你使用add方法时,你把值放到一个结构中,所以使用 `super` 通配符。 这是一个采用数字和整数n的集合的方法将从零开始的前n个整数放入集合中:
|
46 | 46 |
|
47 |
| - ```java |
48 |
| - public static void count(Collection<? super Integer> ints, int n) { |
49 |
| - for (int i = 0; i < n; i++) ints.add(i); |
50 |
| - } |
51 |
| - ``` |
| 47 | +```java |
| 48 | + public static void count(Collection<? super Integer> ints, int n) { |
| 49 | + for (int i = 0; i < n; i++) ints.add(i); |
| 50 | + } |
| 51 | +``` |
52 | 52 |
|
53 | 53 | 由于这使用 `super`,以下所有调用都是合法的:
|
54 | 54 |
|
55 |
| - ```java |
56 |
| - List<Integer> ints = new ArrayList<Integer>(); |
57 |
| - count(ints, 5); |
58 |
| - assert ints.toString().equals("[0, 1, 2, 3, 4]"); |
59 |
| - List<Number> nums = new ArrayList<Number>(); |
60 |
| - count(nums, 5); nums.add(5.0); |
61 |
| - assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]"); |
62 |
| - List<Object> objs = new ArrayList<Object>(); |
63 |
| - count(objs, 5); objs.add("five"); |
64 |
| - assert objs.toString().equals("[0, 1, 2, 3, 4, five]"); |
65 |
| - ``` |
| 55 | +```java |
| 56 | + List<Integer> ints = new ArrayList<Integer>(); |
| 57 | + count(ints, 5); |
| 58 | + assert ints.toString().equals("[0, 1, 2, 3, 4]"); |
| 59 | + List<Number> nums = new ArrayList<Number>(); |
| 60 | + count(nums, 5); nums.add(5.0); |
| 61 | + assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]"); |
| 62 | + List<Object> objs = new ArrayList<Object>(); |
| 63 | + count(objs, 5); objs.add("five"); |
| 64 | + assert objs.toString().equals("[0, 1, 2, 3, 4, five]"); |
| 65 | +``` |
66 | 66 |
|
67 | 67 | 如果 `super` 不被使用,最后两个调用将是不合法的。无论何时您将值放入并从同一结构中获取值,都不应使用通配符。
|
68 | 68 |
|
69 |
| - ```java |
70 |
| - public static double sumCount(Collection<Number> nums, int n) { |
71 |
| - count(nums, n); |
72 |
| - return sum(nums); |
73 |
| - } |
74 |
| - ``` |
| 69 | +```java |
| 70 | + public static double sumCount(Collection<Number> nums, int n) { |
| 71 | + count(nums, n); |
| 72 | + return sum(nums); |
| 73 | + } |
| 74 | +``` |
75 | 75 |
|
76 | 76 | 集合被传递给 `sum` 和 `count`,所以它的元素类型都必须继承 `Number`(按总数要求),`Integer` 的超类(按计数要求)。 唯一满足这两个约束的两个类是
|
77 | 77 | `Number` 和 `Integer`,我们选择了第一个。 以下是一个调用示例:
|
78 | 78 |
|
79 |
| - ```java |
80 |
| - List<Number> nums = new ArrayList<Number>(); |
81 |
| - double sum = sumCount(nums,5); |
82 |
| - assert sum == 10; |
83 |
| - ``` |
| 79 | +```java |
| 80 | + List<Number> nums = new ArrayList<Number>(); |
| 81 | + double sum = sumCount(nums,5); |
| 82 | + assert sum == 10; |
| 83 | +``` |
84 | 84 |
|
85 | 85 | 由于没有通配符,参数必须是 `Number` 的集合。
|
86 | 86 |
|
87 | 87 | 如果您不喜欢在 `Number` 和 `Integer` 之间进行选择,那么您可能会想到,如果 `Java` 允许您使用 `extends` 和 `super` 编写通配符,则不需要选择。 例
|
88 | 88 | 如,我们可以写下以下内容:
|
89 | 89 |
|
90 |
| - ```java |
91 |
| - double sumCount(Collection<? extends Number super Integer> coll, int n) |
92 |
| - // 这在java里面是非法的 |
93 |
| - ``` |
| 90 | +```java |
| 91 | + double sumCount(Collection<? extends Number super Integer> coll, int n) |
| 92 | + // 这在java里面是非法的 |
| 93 | +``` |
94 | 94 |
|
95 | 95 | 然后我们可以在一个数字集合或一个整数集合上调用 `sumCount`。 但 `Java` 不允许这样做。 打乱它的唯一原因是简单,可以想象 `Java` 在将来可能会支持这种表
|
96 | 96 | 示法。 但是,现在,如果你想同时获取和放置不要使用通配符。
|
|
100 | 100 |
|
101 | 101 | 例如,考虑下面的代码片段,它使用一个用扩展通配符声明的列表:
|
102 | 102 |
|
103 |
| - ```java |
104 |
| - List<Integer> ints = new ArrayList<Integer>(); |
105 |
| - ints.add(1); |
106 |
| - ints.add(2); |
107 |
| - List<? extends Number> nums = ints; |
108 |
| - double dbl = sum(nums); // ok |
109 |
| - nums.add(3.14); // compile-time error |
110 |
| - ``` |
| 103 | +```java |
| 104 | + List<Integer> ints = new ArrayList<Integer>(); |
| 105 | + ints.add(1); |
| 106 | + ints.add(2); |
| 107 | + List<? extends Number> nums = ints; |
| 108 | + double dbl = sum(nums); // ok |
| 109 | + nums.add(3.14); // compile-time error |
| 110 | +``` |
111 | 111 |
|
112 | 112 | 调用它求和是好的,因为它从列表中获取值,但调用 `add` 的不是,因为它将一个值放入列表中。 这也是一样,因为否则我们可以添加双整数列表!相反,考虑下面的
|
113 | 113 | 代码片段,它使用一个超级通配符声明的列表:
|
114 | 114 |
|
115 |
| - ```java |
116 |
| - List<Object> objs = new ArrayList<Object>(); |
117 |
| - objs.add(1); |
118 |
| - objs.add("two"); |
119 |
| - List<? super Integer> ints = objs; |
120 |
| - ints.add(3); // ok |
121 |
| - double dbl = sum(ints); // 编译报错 |
122 |
| - ``` |
| 115 | +```java |
| 116 | + List<Object> objs = new ArrayList<Object>(); |
| 117 | + objs.add(1); |
| 118 | + objs.add("two"); |
| 119 | + List<? super Integer> ints = objs; |
| 120 | + ints.add(3); // ok |
| 121 | + double dbl = sum(ints); // 编译报错 |
| 122 | +``` |
123 | 123 |
|
124 | 124 | 现在调用 `add` 是正常的,因为它将一个值放入列表中,但是对 `sum` 的调用不是,因为它从列表中获取值。 这也是一样,因为包含一个字符串的列表的总和是没有
|
125 | 125 | 意义的!
|
|
137 | 137 |
|
138 | 138 | 同样,你也不能从使用超级通配符声明的类型中获取任何东西 - 除了 `Object` 类型的值,它是每个引用类型的超类型:
|
139 | 139 |
|
140 |
| - ```java |
141 |
| - List<Object> objs = Arrays.<Object>asList(1,"two"); |
142 |
| - List<? super Integer> ints = objs; |
143 |
| - String str = ""; |
144 |
| - for (Object obj : ints) str += obj.toString(); |
145 |
| - assert str.equals("1two"); |
146 |
| - ``` |
| 140 | +```java |
| 141 | + List<Object> objs = Arrays.<Object>asList(1,"two"); |
| 142 | + List<? super Integer> ints = objs; |
| 143 | + String str = ""; |
| 144 | + for (Object obj : ints) str += obj.toString(); |
| 145 | + assert str.equals("1two"); |
| 146 | +``` |
147 | 147 |
|
148 | 148 | 你可能会觉得有帮助的想法? 将 `T` 扩展为包含每个类型的一个区间,该区间由下面的 `null` 类型和上面的 `T`(其中 `null` 的类型是每个引用类型的子类型)
|
149 | 149 | 限定。 同样,你可能会想到? `super T` 包含每个类型在由 `T` 和由上面的 `Object` 限定的区间中。
|
|
0 commit comments