|
5 | 5 |
|
6 | 6 | **实例创建**在类实例创建表达式中,如果类型是参数化类型,则没有任何类型参数可能是通配符。 例如,以下是非法的: |
7 | 7 |
|
8 | | - ```java |
9 | | - List<?> list = new ArrayList<?>(); // 编译报错 |
10 | | - Map<String, ? extends Number> map = |
11 | | - new HashMap<String, ? extends Number>(); // 编译报错 |
12 | | - ``` |
| 8 | + ```java |
| 9 | + List<?> list = new ArrayList<?>(); // 编译报错 |
| 10 | + Map<String, ? extends Number> map = new HashMap<String, ? extends Number>(); // 编译报错 |
| 11 | + ``` |
13 | 12 |
|
14 | 13 | 这通常不是困难。 `Get` 和 `Put` 原则告诉我们,如果一个结构体包含通配符,那么我们只应该从中得到值(如果它是一个扩展通配符)或者只将值放入它中(如果它 |
15 | 14 | 是一个超级通配符)。 为了使结构有用,我们必须同时做到这两点。 因此,我们通常以精确的类型创建结构,即使我们使用通配符类型将值放入或从结构中获取值,如 |
16 | 15 | 下例所示: |
17 | 16 |
|
18 | | - ```java |
19 | | - List<Number> nums = new ArrayList<Number>(); |
20 | | - List<? super Number> sink = nums; |
21 | | - List<? extends Number> source = nums; |
22 | | - for (int i=0; i<10; i++) sink.add(i); |
23 | | - double sum=0; for (Number num : source) sum+=num.doubleValue(); |
24 | | - ``` |
| 17 | + ```java |
| 18 | + List<Number> nums = new ArrayList<Number>(); |
| 19 | + List<? super Number> sink = nums; |
| 20 | + List<? extends Number> source = nums; |
| 21 | + for (int i=0; i<10; i++) sink.add(i); |
| 22 | + double sum=0; for (Number num : source) sum+=num.doubleValue(); |
| 23 | + ``` |
25 | 24 |
|
26 | 25 | 这里通配符出现在第二行和第三行,但不在创建列表的第一行。 |
27 | 26 |
|
28 | 27 | 禁止包含通配符的实例创建中只有顶级参数。 允许嵌套通配符。 因此,以下是合法的: |
29 | 28 |
|
30 | | - ```java |
31 | | - List<List<?>> lists = new ArrayList<List<?>>(); |
32 | | - lists.add(Arrays.asList(1,2,3)); |
33 | | - lists.add(Arrays.asList("four","five")); |
34 | | - assert lists.toString().equals("[[1, 2, 3], [four, five]]"); |
35 | | - ``` |
| 29 | + ```java |
| 30 | + List<List<?>> lists = new ArrayList<List<?>>(); |
| 31 | + lists.add(Arrays.asList(1,2,3)); |
| 32 | + lists.add(Arrays.asList("four","five")); |
| 33 | + assert lists.toString().equals("[[1, 2, 3], [four, five]]"); |
| 34 | + ``` |
36 | 35 | |
37 | 36 | 即使列表的列表是以通配符类型创建的,其中的每个单独列表都有一个特定的类型:第一个列表是整数列表,第二个列表是字符串列表。 通配符类型禁止我们将内部列表 |
38 | 37 | 中的元素作为 `Object` 以外的任何类型提取,但由于这是 `toString` 使用的类型,因此此代码的类型很好。 |
39 | 38 |
|
40 | 39 | 记住限制的一种方式是通配符和普通类型之间的关系类似于接口和类通配符之间的关系,接口更普遍,普通类型和类更具体,实例创建需要更具体的信息。 考虑以下三条 |
41 | 40 | 陈述: |
42 | 41 |
|
43 | | - ```java |
44 | | - List<?> list = new ArrayList<Object>(); // ok |
45 | | - List<?> list = new List<Object>() // 编译报错 |
46 | | - List<?> list = new ArrayList<?>() // 编译报错 |
47 | | - ``` |
| 42 | + ```java |
| 43 | + List<?> list = new ArrayList<Object>(); // ok |
| 44 | + List<?> list = new List<Object>() // 编译报错 |
| 45 | + List<?> list = new ArrayList<?>() // 编译报错 |
| 46 | + ``` |
48 | 47 |
|
49 | 48 | 第一个是合法的; 第二个是非法的,因为实例创建表达式需要一个类,而不是一个接口; 第三个是非法的,因为实例创建表达式需要普通类型而不是通配符。 |
50 | 49 |
|
|
53 | 52 |
|
54 | 53 | **泛型方法调用**如果泛型方法调用包含显式类型参数,那么这些类型参数不能是通配符。 例如,假设我们有以下通用方法: |
55 | 54 |
|
56 | | - ```java |
57 | | - class Lists { |
58 | | - public static <T> List<T> factory() { return new ArrayList<T>(); } |
59 | | - } |
60 | | - ``` |
| 55 | + ```java |
| 56 | + class Lists { |
| 57 | + public static <T> List<T> factory() { return new ArrayList<T>(); } |
| 58 | + } |
| 59 | + ``` |
61 | 60 |
|
62 | 61 | 您可以选择推断的类型参数,也可以传递一个明确的类型参数。 以下两项都是合法的: |
63 | 62 |
|
64 | | - ```java |
65 | | - List<?> list = Lists.factory(); |
66 | | - List<?> list = Lists.<Object>factory(); |
67 | | - ``` |
| 63 | + ```java |
| 64 | + List<?> list = Lists.factory(); |
| 65 | + List<?> list = Lists.<Object>factory(); |
| 66 | + ``` |
68 | 67 |
|
69 | 68 | 如果传递一个显式的类型参数,它不能是通配符: |
70 | 69 |
|
71 | 70 | ```java |
72 | | - List<?> list = Lists.<?>factory(); // 编译报错 |
| 71 | + List<?> list = Lists.<?>factory(); // 编译报错 |
73 | 72 | ``` |
74 | 73 |
|
75 | 74 | 和以前一样,可以使用嵌套通配符: |
76 | 75 |
|
77 | 76 | ```java |
78 | | - List<List<?>> = Lists.<List<?>>factory(); // ok |
| 77 | + List<List<?>> = Lists.<List<?>>factory(); // ok |
79 | 78 | ``` |
80 | 79 | |
81 | 80 | 这种限制的动机与之前的相似。 再次,目前还不清楚是否有必要,但这不太可能成为问题。 |
|
84 | 83 | 型参数,则这些类型不能是通配符。例如,这个声明是非法的: |
85 | 84 |
|
86 | 85 | ```java |
87 | | - class AnyList extends ArrayList<?> {...} // 编译报错 |
| 86 | + class AnyList extends ArrayList<?> {...} // 编译报错 |
88 | 87 | ``` |
89 | 88 |
|
90 | 89 | 这也是: |
91 | 90 |
|
92 | 91 | ```java |
93 | | - class AnotherList implements List<?> {...} // 编译报错 |
| 92 | + class AnotherList implements List<?> {...} // 编译报错 |
94 | 93 | ``` |
95 | 94 |
|
96 | 95 | 但是,像以前一样,嵌套通配符是允许的: |
97 | 96 |
|
98 | | - ```java |
99 | | - class NestedList extends ArrayList<List<?>> {...} // ok |
100 | | - ``` |
| 97 | + ```java |
| 98 | + class NestedList extends ArrayList<List<?>> {...} // ok |
| 99 | + ``` |
101 | 100 |
|
102 | 101 | 这种限制的动机与前两种类似。 与以前一样,目前还不清楚是否有必要,但不太可能成为问题。 |
103 | 102 |
|
|
0 commit comments