|
9 | 9 | 回想一下,`2.5` 节介绍了为什么需要物化的一个例子: |
10 | 10 |
|
11 | 11 | ```java |
12 | | - Integer[] ints = new Integer[] {1}; |
13 | | - Number[] nums = ints; |
14 | | - nums[0] = 1.01; // 数组存储异常 |
15 | | - int n = ints[0]; |
| 12 | +Integer[] ints = new Integer[] {1}; |
| 13 | +Number[] nums = ints; |
| 14 | +nums[0] = 1.01; // 数组存储异常 |
| 15 | +int n = ints[0]; |
16 | 16 | ``` |
17 | 17 |
|
18 | 18 | 这将整数数组赋给一个数组数组,然后尝试将一个 `double` 存储到数组数组中。 该尝试引发数组存储异常,因为该检查与实体类型有关。 这也是一样,因为否则最后 |
|
21 | 21 | 下面是一个类似的例子,数组数组被数组列表所取代: |
22 | 22 |
|
23 | 23 | ```java |
24 | | - List<Integer>[] intLists |
25 | | - = (List<Integer>[])new List[] {Arrays.asList(1)}; // 未经检查的转换 |
26 | | - List<? extends Number>[] numLists = intLists; |
27 | | - numLists[0] = Arrays.asList(1.01); |
28 | | - int n = intLists[0].get(0); // 类抛出异常! |
| 24 | +List<Integer>[] intLists = (List<Integer>[])new List[] {Arrays.asList(1)}; // 未经检查的转换 |
| 25 | +List<? extends Number>[] numLists = intLists; |
| 26 | +numLists[0] = Arrays.asList(1.01); |
| 27 | +int n = intLists[0].get(0); // 类抛出异常! |
29 | 28 | ``` |
30 | 29 |
|
31 | 30 | 这将整数列表分配给数组列表,然后尝试将双列表存储到数组列表中。 这次尝试的存储不会失败,即使它应该,因为针对被指定类型的检查是不充分的:被指定的信息只 |
|
34 | 33 | 例 `6-1`。 避免不可接受类型的数组 |
35 | 34 |
|
36 | 35 | ```java |
37 | | - DeceptiveLibrary.java: |
38 | | - import java.util.*; |
39 | | - public class DeceptiveLibrary { |
40 | | - public static List<Integer>[] intLists(int size) { |
41 | | - List<Integer>[] intLists = |
42 | | - (List<Integer>[]) new List[size]; // 未经检查的转换 |
43 | | - for (int i = 0; i < size; i++) |
44 | | - intLists[i] = Arrays.asList(i+1); |
45 | | - return ints; |
46 | | - } |
47 | | - } |
48 | | - |
49 | | - InnocentClient.java: |
50 | | - import java.util.*; |
51 | | - public class InnocentClient { |
52 | | - public static void main(String[] args) { |
53 | | - List<Integer>[] intLists = DeceptiveLibrary.intLists(1); |
54 | | - List<? extends Number>[] numLists = intLists; |
55 | | - numLists[0] = Arrays.asList(1.01); |
56 | | - int i = intLists[0].get(0); // 类抛出异常! |
57 | | - } |
58 | | - } |
| 36 | +DeceptiveLibrary.java: |
| 37 | +import java.util.*; |
| 38 | +public class DeceptiveLibrary { |
| 39 | + public static List<Integer>[] intLists(int size) { |
| 40 | + List<Integer>[] intLists = (List<Integer>[]) new List[size]; // 未经检查的转换 |
| 41 | + for (int i = 0; i < size; i++) |
| 42 | + intLists[i] = Arrays.asList(i+1); |
| 43 | + return ints; |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +InnocentClient.java: |
| 48 | +import java.util.*; |
| 49 | +public class InnocentClient { |
| 50 | + public static void main(String[] args) { |
| 51 | + List<Integer>[] intLists = DeceptiveLibrary.intLists(1); |
| 52 | + List<? extends Number>[] numLists = intLists; |
| 53 | + numLists[0] = Arrays.asList(1.01); |
| 54 | + int i = intLists[0].get(0); // 类抛出异常! |
| 55 | + } |
| 56 | +} |
59 | 57 | ``` |
60 | 58 |
|
61 | 59 | 例 `6-1` 给出了一个类似的例子,分为两类,以说明设计不佳的图书馆如何为无辜的客户创造问题。 名为 `DeceptiveLibrary` 的第一个类定义了一个静态方法,该 |
62 | 60 | 方法返回给定大小的整数列表数组。 由于不允许通用数组的创建,因此使用原始类型 `List` 的组件创建数组,并使用强制类型为组件提供参数化类型 |
63 | 61 | `List<Integer>`。 演员阵容会产生一个未经检查的警告: |
64 | 62 |
|
65 | 63 | ```java |
66 | | - %javac -Xlint:unchecked DeceptiveLibrary.java |
67 | | - DeceptiveLibrary.java:5: warning: [unchecked] unchecked cast |
68 | | - found : java.util.List[] |
69 | | - required: java.util.List<java.lang.Integer>[] |
70 | | - (List<Integer>[]) new List[size]; // unchecked cast |
71 | | - ^ |
72 | | - 1 warning |
| 64 | +%javac -Xlint:unchecked DeceptiveLibrary.java |
| 65 | +DeceptiveLibrary.java:5: warning: [unchecked] unchecked cast |
| 66 | +found : java.util.List[] |
| 67 | +required: java.util.List<java.lang.Integer>[] |
| 68 | + (List<Integer>[]) new List[size]; // unchecked cast |
| 69 | + ^ |
| 70 | +1 warning |
73 | 71 | ``` |
74 | 72 |
|
75 | 73 | 由于该数组确实是一个整数列表数组,因此该数组似乎是合理的,并且您可能认为可以安全地忽略此警告。 正如我们将要看到的,你无视这个警告! |
|
78 | 76 | 运行代码会用双精度列表覆盖整数列表。 尝试从整数列表中提取整数会导致通过擦除隐式插入的强制转换失败: |
79 | 77 |
|
80 | 78 | ```java |
81 | | - %java InnocentClient |
82 | | - Exception in thread "main" java.lang.ClassCastException: java.lang.Double |
83 | | - at InnocentClient.main(InnocentClient.java:7) |
| 79 | +%java InnocentClient |
| 80 | +Exception in thread "main" java.lang.ClassCastException: java.lang.Double |
| 81 | +at InnocentClient.main(InnocentClient.java:7) |
84 | 82 | ``` |
85 | 83 |
|
86 | 84 | 如前一节所述,此错误消息可能会令人困惑,因为该行看起来不包含演员表! |
|
97 | 95 | 即使在Java泛型的设计者中,也要花费一些时间来理解不雅暴露原则的重要性。例如,反射库中的以下两种方法违反了该原则: |
98 | 96 |
|
99 | 97 | ```java |
100 | | - TypeVariable<Class<T>>[] java.lang.Class.getTypeParameters() |
101 | | - TypeVariable<Method>[] java.lang.Reflect.Method.getTypeParameters() |
| 98 | +TypeVariable<Class<T>>[] java.lang.Class.getTypeParameters() |
| 99 | +TypeVariable<Method>[] java.lang.Reflect.Method.getTypeParameters() |
102 | 100 | ``` |
103 | 101 |
|
104 | 102 | 遵循前面的模型,创建自己的Innocent Client版本并不难,它会在没有投射的地方抛出类抛出错误,在这种情况下,正式Java库会播放 `DeceptiveLibrary` 的角 |
|
0 commit comments