1
1
##理解集合Collection
2
2
3
- 先来看看集合的继承关系图,如下图所示:
3
+ 先来看看集合的继承关系图,如下图所示:
4
4
5
5
![ enter image description here] ( https://images.gitbook.cn/ae489970-ca62-11e9-bd50-998f3938aecb )
6
6
18
18
19
19
下面我们分别对集合类进行详细地介绍。
20
20
21
- ###集合使用
21
+ ###List :可重复
22
22
23
- #### 1) Vector
23
+ > List是一个非常常用的数据类型,一共有以下三种实现类,分别为: ** Vector 、ArrayList、LinkedList ** 。
24
24
25
- Vector 是 Java 早期提供的线程安全的有序集合,如果不需要线程安全,不建议使用此集合,毕竟同步是有线程开销的。
25
+ #### Vector
26
26
27
- 使用示例代码:
27
+ Vector内部是基于数组实现, ** 线程安全 ** (synchronized关键字),也就是说在同一个时刻只能允许一个线程对Vector进行写操作,以保证在多线程环境下数据的一致性,但是频繁的进行加锁和释放锁操作,会导致Vector的 ** 读写效率比较底 ** 。
28
28
29
- ```
30
- Vector vector = new Vector();
31
- vector.add("dog");
32
- vector.add("cat");
33
- vector.remove("cat");
34
- System.out.println(vector);
35
- ```
36
-
37
- 程序执行结果:` [dog] `
38
-
39
- ####2)ArrayList
40
-
41
- ArrayList 是最常见的非线程安全的有序集合,因为内部是数组存储的,所以随机访问效率很高,但非尾部的插入和删除性能较低,如果在中间插入元素,之后的所有元素都要后移。ArrayList 的使用与 Vector 类似。
29
+ ####ArrayList
42
30
43
- #### 3)LinkedList
31
+ ArrayList使用非常广泛,内部也是基于 ** 数组 ** 实现, ** 线程不安全 ** ,ArrayList ** 不适合随机插入和删除的操作 ** ,更 ** 适合随机查找和遍历的操作 ** 。
44
32
45
- LinkedList 是使用双向链表数据结构实现的,因此增加和删除效率比较高,而随机访问效率较差。
33
+ #### LinkedList
46
34
47
- LinkedList 除了包含以上两个类的操作方法之外,还新增了几个操作方法,如 offer() 、peek() 等,具体详情,请参考以下代码:
35
+ LinkedList采用 ** 双向链表 ** 结构存储元素, ** 随机插入和删除效率高 ** , ** 随机访问的效率低 ** 。
48
36
49
- ```
50
- LinkedList linkedList = new LinkedList();
51
- // 添加元素
52
- linkedList.offer("bird");
53
- linkedList.push("cat");
54
- linkedList.push("dog");
55
- // 获取第一个元素
56
- System.out.println(linkedList.peek());
57
- // 获取第一个元素,并删除此元素
58
- System.out.println(linkedList.poll());
59
- System.out.println(linkedList);
60
- ```
61
-
62
- 程序的执行结果:
37
+ ###Set : 不可重复
63
38
64
- ```
65
- dog
66
- dog
67
- [cat, bird]
68
- ```
39
+ > Set 的核心价值观就是独一无二,适合存储无序且值不相等的元素。对象的相等性本质上就是对象的HashCode值相等,在Java中根据对象的内存地址计算的对象的HashCode值。如果想要比较两个对象是否相等,则必然同时覆盖对象的hashCode方法和equals方法,并且hashCode方法和equals方法的返回值也必须一样。
69
40
70
- ####4) HashSet
41
+ ####HashSet
71
42
72
- HashSet是一个没有重复元素的集合。 虽然它是 Set 集合的子类,实际却为 HashMap的实例, 相关源码如下:
43
+ HashSet是一个 ** 没有重复元素 ** 的集合,存放的是散列值,它按照元素的散列值来存取元素的。元素的散列值是通过元素的hashCode方法计算得到的,HashSet 首先判断两个元素的散列值是否相等,如果散列值相等,在用equals方法比较,如果equals也返回true,则是同一个元素,否则就不是同一个元素。 虽然它是 Set 集合的子类,** 基于 HashMap的实现, ** 相关源码如下:
73
44
74
- ```
45
+ ``` java
75
46
public HashSet() {
76
47
map= new HashMap<> ();
77
48
}
78
49
```
79
50
80
- 因此 HashSet是无序集合 ,没有办法保证元素的顺序性。
51
+ 因此 HashSet是 ** 无序 ** 集合 ,没有办法保证元素的顺序性。
81
52
82
- HashSet 默认容量为 16,每次扩充 0.75 倍,相关源码如下:
53
+ ** HashSet 默认容量为 16,每次扩充 0.75 倍** ,相关源码如下:
83
54
84
- ```
55
+ ``` java
85
56
public HashSet(Collection<? extendsE > c) {
86
57
map= new HashMap<> (Math . max((int ) (c. size()/ .75f )+ 1 ,16 ));
87
58
addAll(c);
88
59
}
89
60
```
90
61
91
- HashSet 的使用与 Vector 类似。
92
-
93
- ####5)TreeSet
94
-
95
- TreeSet 集合实现了自动排序,也就是说 TreeSet 会把你插入数据进行自动排序。
96
-
97
- 示例代码如下:
98
-
99
- ```
100
- TreeSet treeSet = new TreeSet();
101
- treeSet.add("dog");
102
- treeSet.add("camel");
103
- treeSet.add("cat");
104
- treeSet.add("ant");
105
- System.out.println(treeSet);
106
- ```
107
-
108
- 程序执行结果:` [ant, camel, cat, dog] `
109
-
110
- 可以看出,TreeSet 的使用与 Vector 类似,只是实现了自动排序。
111
-
112
- ####6)LinkedHashSet
113
-
114
- LinkedHashSet 是按照元素的 hashCode 值来决定元素的存储位置,但同时又使用链表来维护元素的次序,这样使得它看起来像是按照插入顺序保存的。
62
+ ####TreeSet
115
63
116
- LinkedHashSet 的使用与 Vector 类似。
117
-
118
- ###集合与数组
119
-
120
- 集合和数组的转换可使用 toArray() 和 Arrays.asList() 来实现,请参考以下代码示例:
121
-
122
- ``` java
123
- List<String > list= new ArrayList ();
124
- list. add(" cat" );
125
- list. add(" dog" );
126
- // 集合转数组
127
- String [] arr= list. toArray(new String [list. size()]);
128
- // 数组转集合
129
- List<String > list2= Arrays . asList(arr);
130
- ```
64
+ TreeSet 基于二叉树的原理对新添加的对象按照指定的顺序排序,每添加一个对象都会进行排序 ,并将对象插入二叉树的指定位置。
131
65
132
- 集合与数组的区别,可以参考 [ 「数组和排序算法的应用 + 面试题」 ] ( https://gitbook.cn/gitchat/column/5d493b4dcb702a087ef935d9/topic/5d4d7ea069004b174ccfffef ) 的内容。
66
+ #### LinkedHashSet
133
67
134
- ### 集合排序
68
+ LinkedHashSet 继承HashSet,HashMap实现数据存储,双向链表记录顺序。LinkedHashSet 底层使用的LinkedHashMap存储元素,它继承了HashMap。
135
69
136
- 在 Java 语言中排序提供了两种方式:Comparable 和 Comparator,它们的区别也是常见的面试题之一。下面我们彻底地来了解一下 Comparable 和 Comparator 的使用与区别。
70
+ ### Quenue
137
71
138
- #### 1)Comparable
72
+ Quenue是队列结构,Java中的常用队列如下:
139
73
140
- Comparable 位于 java.lang 包下,是一个排序接口,也就是说如果一个类实现了 Comparable 接口,就意味着该类有了排序功能。
141
-
142
- Comparable 接口只包含了一个函数,定义如下:
143
-
144
- ```
145
- package java.lang;
146
- import java.util.*;
147
- public interface Comparable {
148
- public int compareTo(T o);
149
- }
150
- ```
151
-
152
- ** Comparable 使用示例** ,请参考以下代码:
153
-
154
- ``` xml
155
- class ComparableTest {
156
- public static void main(String[] args) {
157
- Dog[] dogs = new Dog[]{
158
- new Dog("老旺财", 10),
159
- new Dog("小旺财", 3),
160
- new Dog("二旺财", 5),
161
- };
162
- // Comparable 排序
163
- Arrays.sort(dogs);
164
- for (Dog d : dogs) {
165
- System.out.println(d.getName() + ":" + d.getAge());
166
- }
167
- }
168
- }
169
- class Dog implements Comparable<Dog > {
170
- private String name;
171
- private int age;
172
- @Override
173
- public int compareTo(Dog o) {
174
- return age - o.age;
175
- }
176
- public Dog(String name, int age) {
177
- this.name = name;
178
- this.age = age;
179
- }
180
- public String getName() {
181
- return name;
182
- }
183
- public int getAge() {
184
- return age;
185
- }
186
- }
187
- ```
188
-
189
- 程序执行结果:
190
-
191
- ```
192
- 小旺财:3
193
- 二旺财:5
194
- 老旺财:10
195
- ```
196
-
197
- 如果 Dog 类未实现 Comparable 执行代码会报程序异常的信息,错误信息为:
198
-
199
- > Exception in thread "main" java.lang.ClassCastException: xxx cannot be cast to java.lang.Comparable
200
- >
201
- > compareTo() 返回值有三种:
202
-
203
- - e1.compareTo(e2) > 0 即 e1 > e2;
204
- - e1.compareTo(e2) = 0 即 e1 = e2;
205
- - e1.compareTo(e2) < 0 即 e1 < e2。
206
-
207
- ####2)Comparator
208
-
209
- Comparator 是一个外部比较器,位于 java.util 包下,之所以说 Comparator 是一个外部比较器,是因为它无需在比较类中实现 Comparator 接口,而是要新创建一个比较器类来进行比较和排序。
210
-
211
- Comparator 接口包含的主要方法为 compare(),定义如下:
212
-
213
- ```
214
- public interface Comparator<T> {
215
- int compare(T o1, T o2);
216
- }
217
- ```
218
-
219
- ** Comparator 使用示例** ,请参考以下代码:
220
-
221
- ``` xml
222
- class ComparatorTest {
223
- public static void main(String[] args) {
224
- Dog[] dogs = new Dog[]{
225
- new Dog("老旺财", 10),
226
- new Dog("小旺财", 3),
227
- new Dog("二旺财", 5),
228
- };
229
- // Comparator 排序
230
- Arrays.sort(dogs,new DogComparator());
231
- for (Dog d : dogs) {
232
- System.out.println(d.getName() + ":" + d.getAge());
233
- }
234
- }
235
- }
236
- class DogComparator implements Comparator<Dog > {
237
- @Override
238
- public int compare(Dog o1, Dog o2) {
239
- return o1.getAge() - o2.getAge();
240
- }
241
- }
242
- class Dog {
243
- private String name;
244
- private int age;
245
- public Dog(String name, int age) {
246
- this.name = name;
247
- this.age = age;
248
- }
249
- public String getName() {
250
- return name;
251
- }
252
- public int getAge() {
253
- return age;
254
- }
255
- }
256
- ```
257
-
258
- 程序执行结果:
259
-
260
- ```
261
- 小旺财:3
262
- 二旺财:5
263
- 老旺财:10
264
- ```
74
+ - ArrayBlockingQueue : 基于数组数据结构实现的有界阻塞队列。
75
+ - LinkedBlockingQueue : 基于链表数据结构实现的有界阻塞队列。
76
+ - PriorityBlockingQueue : 支持优先级排序的无界阻塞队列。
77
+ - DelayQueue : 支持延迟操作的无界阻塞队列。
78
+ - SynchronousQueue : 用于线程同步的阻塞队列。
79
+ - LinkedTransferQueue : 基于链表数据结构实现的无界阻塞队列。
80
+ - LinkedBlockingDeque : 基于链表数据结构实现双向阻塞队列。 吧
265
81
266
82
###相关面试题
267
83
@@ -283,21 +99,21 @@ class Dog {
283
99
284
100
Vector 默认容量源码:
285
101
286
- ```
102
+ ``` java
287
103
public Vector() {
288
104
this (10 );
289
105
}
290
106
```
291
107
292
108
ArrayList 默认容量源码:
293
109
294
- ```
110
+ ``` java
295
111
private static final int DEFAULT_CAPACITY = 10 ;
296
112
```
297
113
298
114
Vector 容量扩充默认增加 1 倍,源码如下:
299
115
300
- ```
116
+ ``` java
301
117
private void grow(int minCapacity) {
302
118
// overflow-conscious code
303
119
int oldCapacity= elementData. length;
@@ -315,7 +131,7 @@ private void grow(int minCapacity) {
315
131
316
132
ArrayList 容量扩充默认增加大概 0.5 倍(oldCapacity + (oldCapacity >> 1)),源码如下(JDK 8):
317
133
318
- ```
134
+ ``` java
319
135
private void grow(int minCapacity) {
320
136
// overflow-conscious code
321
137
int oldCapacity= elementData. length;
@@ -377,15 +193,15 @@ public boolean add(E e) {
377
193
378
194
####10.执行以下程序会输出什么结果?为什么?
379
195
380
- ```
196
+ ``` java
381
197
Integer num= 10 ;
382
198
Integer num2= 5 ;
383
199
System . out. println(num. compareTo(num2));
384
200
```
385
201
386
202
答:程序输出的结果是` 1 ` ,因为 Integer 默认实现了 compareTo 方法,定义了自然排序规则,所以当 num 比 num2 大时会返回 1,Integer 相关源码如下:
387
203
388
- ```
204
+ ``` java
389
205
public int compareTo(Integer anotherInteger) {
390
206
return compare(this . value, anotherInteger. value);
391
207
}
@@ -398,7 +214,7 @@ public static int compare(int x, int y) {
398
214
399
215
答:可以使用集合中的 Stack 实现,Stack 是标准的后进先出的栈结构,使用 Stack 中的 pop() 方法返回栈顶元素并删除该元素,示例代码如下。
400
216
401
- ```
217
+ ``` java
402
218
Stack stack= new Stack ();
403
219
stack. push(" a" );
404
220
stack. push(" b" );