|
10 | 10 | 这里是第二次尝试将集合转换为数组,这次使用未经检查的转换,并添加了测试代码:
|
11 | 11 |
|
12 | 12 | ```java
|
13 |
| - import java.util.*; |
14 |
| - class Wrong { |
15 |
| - public static<T> T[] toArray(Collection<T> c) { |
16 |
| - T[] a = (T[])new Object[c.size()]; // 未经检查的转换 |
17 |
| - int i=0; for (T x : c) a[i++] = x; |
18 |
| - return a; |
19 |
| - } |
20 |
| - public static void main(String[] args) { |
21 |
| - List<String> strings = Arrays.asList("one","two"); |
22 |
| - String[] a = toArray(strings); // 类抛出错误 |
23 |
| - } |
24 |
| - } |
| 13 | +import java.util.*; |
| 14 | +class Wrong { |
| 15 | + public static<T> T[] toArray(Collection<T> c) { |
| 16 | + T[] a = (T[])new Object[c.size()]; // 未经检查的转换 |
| 17 | + int i=0; for (T x : c) a[i++] = x; |
| 18 | + return a; |
| 19 | + } |
| 20 | + public static void main(String[] args) { |
| 21 | + List<String> strings = Arrays.asList("one","two"); |
| 22 | + String[] a = toArray(strings); // 类抛出错误 |
| 23 | + } |
| 24 | +} |
25 | 25 | ```
|
26 | 26 |
|
27 | 27 | 上一节中的代码使用短语 `new T[c.size()]` 创建数组,导致编译器报告通用数组创建错误。 新代码改为分配一个对象数组并将其转换为 `T []` 类型,这会导致编
|
28 | 28 | 译器发出未经检查的强制转换警告:
|
29 | 29 |
|
30 | 30 | ```java
|
31 |
| - % javac -Xlint Wrong.java |
32 |
| - Wrong.java:4: warning: [unchecked] 未经检查的转换 |
33 |
| - found : java.lang.Object[] |
34 |
| - required: T[] |
35 |
| - T[] a = (T[])new Object[c.size()]; // 未经检查的转换 |
36 |
| - ^ |
37 |
| - 1 warning |
| 31 | +% javac -Xlint Wrong.java |
| 32 | +Wrong.java:4: warning: [unchecked] 未经检查的转换 |
| 33 | +found : java.lang.Object[] |
| 34 | +required: T[] |
| 35 | + T[] a = (T[])new Object[c.size()]; // 未经检查的转换 |
| 36 | + ^ |
| 37 | +1 warning |
38 | 38 | ```
|
39 | 39 |
|
40 | 40 | 正如你从这个程序选择的名字中猜出的那样,这个警告不应该被忽略。 事实上,运行这个程序给出了以下结果:
|
41 | 41 |
|
42 | 42 | ```java
|
43 |
| - % java Wrong |
44 |
| - Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; |
45 |
| - at Wrong.main(Wrong.java:11) |
| 43 | +% java Wrong |
| 44 | +Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; |
| 45 | + at Wrong.main(Wrong.java:11) |
46 | 46 | ```
|
47 | 47 |
|
48 | 48 | 难懂的短语 `[Ljava.lang.Object` 是数组的指定类型,其中 `[L` 表示它是引用类型的数组,而 `java.lang.Object` 是数组的组件类型。 类转换错误消息引用包
|
|
52 | 52 | 在调用 `toArray` 时插入相应的强制转换,从而生成以下等效代码:
|
53 | 53 |
|
54 | 54 | ```java
|
55 |
| - import java.util.*; |
56 |
| - class Wrong { |
57 |
| - public static Object[] toArray(Collection c) { |
58 |
| - Object[] a = (Object[])new Object[c.size()]; // unchecked cast |
59 |
| - int i=0; for (Object x : c) a[i++] = x; |
60 |
| - return a; |
61 |
| - } |
62 |
| - public static void main(String[] args) { |
63 |
| - List strings = Arrays.asList(args); |
64 |
| - String[] a = (String[])toArray(strings); // class cast error |
65 |
| - } |
66 |
| - } |
| 55 | +import java.util.*; |
| 56 | +class Wrong { |
| 57 | + public static Object[] toArray(Collection c) { |
| 58 | + Object[] a = (Object[])new Object[c.size()]; // unchecked cast |
| 59 | + int i=0; for (Object x : c) a[i++] = x; |
| 60 | + return a; |
| 61 | + } |
| 62 | + public static void main(String[] args) { |
| 63 | + List strings = Arrays.asList(args); |
| 64 | + String[] a = (String[])toArray(strings); // class cast error |
| 65 | + } |
| 66 | +} |
67 | 67 | ```
|
68 | 68 |
|
69 | 69 | 类型擦除将未选中的转换转换为 `T []` 转换为 `Object []` 的转换,并在调用 `toArray` 时将转换插入 `String []`。 运行时,这些转换中的第一个成功。 但
|
|
87 | 87 | 以下是实施替代方案的代码:
|
88 | 88 |
|
89 | 89 | ```java
|
90 |
| - import java.util.*; |
91 |
| - class Right { |
92 |
| - public static <T> T[] Array(toCollection<T> c, T[] a) { |
93 |
| - if (a.length< c.size()) |
94 |
| - a = (T[])java.lang.reflect.Array. // unchecked cast |
95 |
| - newInstance(a.get Class().getComponentType(), c.size()); |
96 |
| - int i=0; for (T x : c) a[i++] = x; |
97 |
| - if (i< a.length) a[i] = null; |
98 |
| - return a; |
99 |
| - } |
100 |
| - public static void main(String[] args) { |
101 |
| - List<String> strings = Arrays.asList("one", "two"); |
102 |
| - String[] a = toArray(strings, new String[0]); |
103 |
| - assert Arrays.toString(a).equals("[one, two]"); |
104 |
| - String[] b = new String[] { "x","x","x","x" }; |
105 |
| - toArray(strings, b); |
106 |
| - assert Arrays.toString(b).equals("[one, two, null, x]"); |
107 |
| - } |
108 |
| - } |
| 90 | +import java.util.*; |
| 91 | +class Right { |
| 92 | + public static <T> T[] Array(toCollection<T> c, T[] a) { |
| 93 | + if (a.length< c.size()) |
| 94 | + a = (T[])java.lang.reflect.Array. // unchecked cast |
| 95 | + newInstance(a.get Class().getComponentType(), c.size()); |
| 96 | + int i=0; for (T x : c) a[i++] = x; |
| 97 | + if (i< a.length) |
| 98 | + a[i] = null; |
| 99 | + return a; |
| 100 | + } |
| 101 | + public static void main(String[] args) { |
| 102 | + List<String> strings = Arrays.asList("one", "two"); |
| 103 | + String[] a = toArray(strings, new String[0]); |
| 104 | + assert Arrays.toString(a).equals("[one, two]"); |
| 105 | + String[] b = new String[] { "x","x","x","x" }; |
| 106 | + toArray(strings, b); |
| 107 | + assert Arrays.toString(b).equals("[one, two, null, x]"); |
| 108 | + } |
| 109 | +} |
109 | 110 | ```
|
110 | 111 |
|
111 | 112 | 这使用反射库中的三个方法来分配一个与旧数组具有相同组件类型的新数组:方法 `getClass`(在 `java.lang.Object` 中)返回表示数组类型的 `Class` 对象
|
|
127 | 128 | 集合框架包含两个将集合转换为数组的方法,类似于我们刚刚讨论的那个:
|
128 | 129 |
|
129 | 130 | ```java
|
130 |
| - interface Collection<E> { |
131 |
| - ... |
132 |
| - public Object[] toArray(); |
133 |
| - public <T> T[] toArray(T[] a) |
134 |
| - } |
| 131 | +interface Collection<E> { |
| 132 | + ... |
| 133 | + public Object[] toArray(); |
| 134 | + public <T> T[] toArray(T[] a) |
| 135 | +} |
135 | 136 | ```
|
136 | 137 |
|
137 | 138 | 第一个方法返回一个带有指定组件类型 `Object` 的数组,而第二个方法从参数数组中复制指定组件类型,就像上面的静态方法一样。 就像那种方法一样,如果有空间
|
|
153 | 154 | 需要未经检查的转换。
|
154 | 155 |
|
155 | 156 | ```java
|
156 |
| - import java.util.*; |
157 |
| - class RightWithClass { |
158 |
| - public static <T> T[] toArray(Collection<T> c, Class<T> k) { |
159 |
| - T[] a = (T[])java.lang.reflect.Array. // unchecked cast |
160 |
| - newInstance(k, c.size()); |
161 |
| - int i=0; for (T x : c) a[i++] = x; |
162 |
| - return a; |
163 |
| - } |
164 |
| - public static void main(String[] args) { |
165 |
| - List<String> strings = Arrays.asList("one", "two"); |
166 |
| - String[] a = toArray(strings, String.class); |
167 |
| - assert Arrays.toString(a).equals("[one, two]"); |
168 |
| - } |
169 |
| - } |
| 157 | +import java.util.*; |
| 158 | +class RightWithClass { |
| 159 | + public static <T> T[] toArray(Collection<T> c, Class<T> k) { |
| 160 | + T[] a = (T[])java.lang.reflect.Array. // unchecked cast |
| 161 | + newInstance(k, c.size()); |
| 162 | + int i=0; for (T x : c) a[i++] = x; |
| 163 | + return a; |
| 164 | + } |
| 165 | + public static void main(String[] args) { |
| 166 | + List<String> strings = Arrays.asList("one", "two"); |
| 167 | + String[] a = toArray(strings, String.class); |
| 168 | + assert Arrays.toString(a).equals("[one, two]"); |
| 169 | + } |
| 170 | +} |
170 | 171 | ```
|
171 | 172 |
|
172 | 173 | 转换方法现在传递类标记 `String.class` 而不是字符串数组。
|
|
0 commit comments