Skip to content

Commit a3f7d6f

Browse files
authored
Update 05_Arrays.md
1 parent 2ed452c commit a3f7d6f

File tree

1 file changed

+39
-51
lines changed

1 file changed

+39
-51
lines changed

ch02/05_Arrays.md

+39-51
Original file line numberDiff line numberDiff line change
@@ -3,95 +3,83 @@
33

44
### 数组
55

6-
-`Java`中对列表和数组的处理进行比较是有益的,同时牢记替换原则和获取和放置原则。
7-
-`Java`中,数组的子类型是协变的,这意味着当`S``T`的子类型时,类型`S []`被认为是`T []`的一个子类型。
8-
考虑下面的代码片段,它分配一个整数数组,分配一个数组 的数字,然后尝试在数组中分配一个`double`
6+
`Java` 中对列表和数组的处理进行比较是有益的,同时牢记替换原则和获取和放置原则。
7+
8+
`Java` 中,数组的子类型是协变的,这意味着当 `S``T` 的子类型时,类型 `S []` 被认为是 `T []` 的一个子类型。考虑下面的代码片段,它分配一个整数
9+
数组,分配一个数组 的数字,然后尝试在数组中分配一个 `double`
910

1011
```java
1112
Integer[] ints = new Integer[] {1,2,3};
1213
Number[] nums = ints;
1314
nums[2] = 3.14; // array store exception
1415
assert Arrays.toString(ints).equals("[1, 2, 3.14]"); // uh oh!
1516
```
16-
- 这个程序有什么问题,因为它把一个整数数组放到一个`double`中!哪里有问题?
17-
由于`Integer []`被认为是`Number []`的子类型,所以根据替换原则,
18-
第二行的赋值必须是合法的。 相反,问题出现在第三行,并在运行时被捕获。
19-
当一个数组被分配时(如在第一行),它被标记为它的被指定的类型(它的组件类型的运行时表示,
20-
在这个例子中是`Integer`),并且每次数组被分配到 第三行),如果指定的类型与指定的值不兼容,
21-
则会引发数组存储异常(在这种情况下,`double`不能存储到`Integer`数组中)。
17+
18+
这个程序有什么问题,因为它把一个整数数组放到一个 `double` 中!哪里有问题? 由于 `Integer []` 被认为是 `Number []` 的子类型,所以根据替换原则,第二
19+
行的赋值必须是合法的。 相反,问题出现在第三行,并在运行时被捕获。 当一个数组被分配时(如在第一行),它被标记为它的被指定的类型(它的组件类型的运行时
20+
表示,在这个例子中是 `Integer`),并且每次数组被分配到 第三行),如果指定的类型与指定的值不兼容,则会引发数组存储异常(在这种情况下,`double` 不能存
21+
储到 `Integer` 数组中)。
2222

23-
- 相比之下,泛型的子类型关系是不变的,意味着类型`List<S>`不被认为是`List<T>`的子类型,
24-
除了`S``T`相同的普通情况。 这是一个类似于前一个的代码片段,用列表替换数组:
23+
相比之下,泛型的子类型关系是不变的,意味着类型 `List<S>` 不被认为是 `List<T>` 的子类型,除了 `S``T` 相同的普通情况。 这是一个类似于前一个的代
24+
码片段,用列表替换数组:
2525

2626
```java
2727
List<Integer> ints = Arrays.asList(1,2,3);
2828
List<Number> nums = ints; // compile-time error
2929
nums.set(2, 3.14);
3030
assert ints.toString().equals("[1, 2, 3.14]"); // uh oh!
3131
```
32-
- 由于`List<Integer>`不被认为是`List<Number>`的子类型,
33-
因此在第二行而不是第三行检测到问题,并且在编译时检测到,而不是在运行时检测到。
3432

35-
- 通配符重新引入泛型的协变子类型,在当S是T的子类型时,这种类型中`List<S>`被认为是`List<? extends T>`的子类型?
36-
这是片段的第三个变体:
33+
由于 `List<Integer>` 不被认为是 `List<Number>` 的子类型,因此在第二行而不是第三行检测到问题,并且在编译时检测到,而不是在运行时检测到。
34+
35+
通配符重新引入泛型的协变子类型,在当S是T的子类型时,这种类型中 `List<S>` 被认为是 `List<? extends T>` 的子类型? 这是片段的第三个变体:
3736

3837
```java
3938
List<Integer> ints = Arrays.asList(1,2,3);
4039
List<? extends Number> nums = ints;
4140
nums.set(2, 3.14); // compile-time error
4241
assert ints.toString().equals("[1, 2, 3.14]"); // uh oh!
4342
```
44-
- 和数组一样,第三行是错误的,但是与数组相比,这个问题在编译时被检测到,
45-
而不是运行时。 该分配违反了“获取和放置原则”,因为您不能将值放入使用`extends`通配符声明的类型中。
43+
44+
和数组一样,第三行是错误的,但是与数组相比,这个问题在编译时被检测到,而不是运行时。 该分配违反了“获取和放置原则”,因为您不能将值放入使用 `extends`
45+
通配符声明的类型中。
4646

47-
- 通配符还引入了泛型的逆变分类,当`S``T`的超类型(而不是子类型)时,
48-
这种类型`List<S>`是被认为是`List<? super T>`一个子类型? 。 数组不支持逆分类。
49-
例如,回想一下,方法`count`接受了一个类型`Collection<? super Integer>`的参数。
50-
并填充整数。 因为`Java`不允许你编写`(?super Integer)[]`,所以没有与数组做同样的方法。
47+
通配符还引入了泛型的逆变分类,当 `S``T` 的超类型(而不是子类型)时,这种类型 `List<S>` 是被认为是 `List<? super T>` 一个子类型? 。 数组不支持
48+
逆分类。 例如,回想一下,方法 `count` 接受了一个类型 `Collection<? super Integer>` 的参数。 并填充整数。 因为 `Java` 不允许你编写
49+
`(?super Integer)[]`,所以没有与数组做同样的方法。
5150

52-
- 在编译时而不是在运行时检测问题会带来两个优点,一个小问题和一个主要问题。
53-
次要优点是它更有效率。 系统不需要在运行时随身携带一个元素类型的描述,
54-
而且每次执行一个数组赋值时,系统都不需要检查这个描述。
55-
主要优点是编译器检测到一个常见的错误族。 这改善了程序生命周期的各个方面:
56-
编码,调试,测试和维护都变得更简单,更快速,而且更轻量级。
51+
在编译时而不是在运行时检测问题会带来两个优点,一个小问题和一个主要问题。 次要优点是它更有效率。 系统不需要在运行时随身携带一个元素类型的描述,而且每
52+
次执行一个数组赋值时,系统都不需要检查这个描述。 主要优点是编译器检测到一个常见的错误族。 这改善了程序生命周期的各个方面:编码,调试,测试和维护都变
53+
得更简单,更快速,而且更轻量级。
5754

58-
- 除了错误之前被捕获的事实之外,还有许多其他原因可以将收集类更倾向于数组。
59-
集合比数组更灵活。数组支持的唯一操作是获取或设置一个组件,并且该表示是固定的。
60-
集合支持许多额外的操作,包括测试遏制,添加和删除元素,比较或合并两个集合,
61-
以及提取列表的子列表。集合可以是列表(其中的顺序是重要的,元素可以重复)
62-
或集合(顺序不重要,元素可能不重复),可以使用许多表示,包括数组,链表,
63-
树和散列表。最后,便利类Collections和Arrays的比较表明,集合提供了非数组提供的许多操作,
64-
包括旋转或打乱列表的操作,查找集合的最大值以及使集合不可修改或同步。
55+
除了错误之前被捕获的事实之外,还有许多其他原因可以将收集类更倾向于数组。集合比数组更灵活。数组支持的唯一操作是获取或设置一个组件,并且该表示是固定
56+
的。集合支持许多额外的操作,包括测试遏制,添加和删除元素,比较或合并两个集合,以及提取列表的子列表。集合可以是列表(其中的顺序是重要的,元素可以重
57+
复)或集合(顺序不重要,元素可能不重复),可以使用许多表示,包括数组,链表,树和散列表。最后,便利类 `Collections``Arrays` 的比较表明,集合提供
58+
了非数组提供的许多操作,包括旋转或打乱列表的操作,查找集合的最大值以及使集合不可修改或同步。
6559

66-
- 尽管如此,还是有少数情况下数组比数据集更受欢迎。 原始类型的数组更有效率,
67-
因为它们不涉及拳击; 并分配到这样的数组不需要检查数组存储异常,
68-
因为基元类型的数组没有子类型。 尽管检查了数组存储异常,
69-
即使是使用当前代编译器的引用类型数组也可能比集合类更有效,
70-
所以您可能希望在关键的内部循环中使用数组。 与往常一样,
71-
您应该测量性能来验证这样的设计,尤其是因为未来的编译器可能会专门优化收集类。
72-
最后,在某些情况下,出于兼容性的原因,数组可能是优选。
60+
尽管如此,还是有少数情况下数组比数据集更受欢迎。 原始类型的数组更有效率,因为它们不涉及拳击; 并分配到这样的数组不需要检查数组存储异常,因为基元类型的
61+
数组没有子类型。 尽管检查了数组存储异常,即使是使用当前代编译器的引用类型数组也可能比集合类更有效,所以您可能希望在关键的内部循环中使用数组。 与往常
62+
一样,您应该测量性能来验证这样的设计,尤其是因为未来的编译器可能会专门优化收集类。 最后,在某些情况下,出于兼容性的原因,数组可能是优选。
7363

74-
- 总而言之,最好在编译时检测错误,而不是在运行时检测错误,但是`Java`数组在运行时被强制检测到某些错误,
75-
因为决定做出数组子类型协变。 这是一个很好的决定? 在泛型出现之前,这是绝对必要的。
76-
例如,看下面的方法,这些方法用于对任何数组进行排序或使用给定值填充数组:
64+
总而言之,最好在编译时检测错误,而不是在运行时检测错误,但是 `Java` 数组在运行时被强制检测到某些错误,因为决定做出数组子类型协变。 这是一个很好的决
65+
定? 在泛型出现之前,这是绝对必要的。 例如,看下面的方法,这些方法用于对任何数组进行排序或使用给定值填充数组:
7766

7867
```java
7968
public static void sort(Object[] a);
8069
public static void fill(Object[] a, Object val);
8170
```
82-
- 由于协变,这些方法可以用来排序或填充任何引用类型的数组。 没有协变性,
83-
没有泛型,就没有办法声明适用于所有类型的方法。 但是,现在我们已经有了泛型,
84-
协变阵列就不再需要了。 现在我们可以给这些方法以下签名,直接说明它们适用于所有类型:
71+
72+
由于协变,这些方法可以用来排序或填充任何引用类型的数组。 没有协变性,没有泛型,就没有办法声明适用于所有类型的方法。 但是,现在我们已经有了泛型,协变
73+
阵列就不再需要了。 现在我们可以给这些方法以下签名,直接说明它们适用于所有类型:
8574

8675
```java
8776
public static <T> void sort(T[] a);
8877
public static <T> void fill(T[] a, T val);
8978
```
90-
- 从某种意义上讲,协变数组是早期`Java`版本中缺乏泛型的人为因素。 一旦你有泛型,协变数组可能是错误的设计选择,
91-
保留它们的唯一原因是向后兼容。
9279

93-
- 第6.4节 - 第6.8节讨论泛型和数组之间的不方便的交互。 出于多种目的,
94-
将数组视为一个已弃用的类型可能是明智的。我们回到6.9节的这一点。
80+
从某种意义上讲,协变数组是早期 `Java` 版本中缺乏泛型的人为因素。 一旦你有泛型,协变数组可能是错误的设计选择,保留它们的唯一原因是向后兼容。
81+
82+
`6.4` 节 - 第 `6.8` 节讨论泛型和数组之间的不方便的交互。 出于多种目的,将数组视为一个已弃用的类型可能是明智的。我们回到 `6.9` 节的这一点。
9583

96-
《《《 [上一节](06_Wildcards_Versus_Type_Parameters.md) <br/>
84+
《《《 [下一节](06_Wildcards_Versus_Type_Parameters.md) <br/>
9785
《《《 [返回首页](../README.md)

0 commit comments

Comments
 (0)