9
9
* [1.1.3 如何选用集合?](#-1)
10
10
* [1.1.4 为什么要使用集合?](#-1)
11
11
* [ 1.2 Iterator迭代器接口] ( #Iterator )
12
+ * [ 1.2.1 为什么要使用迭代器] ( #1.2.1为什么要使用迭代器 )
12
13
* [ 1.3 Collection子接口之List] ( #CollectionList )
13
14
* [ 1.3.1 Arraylist 与 LinkedList 区别?](#ArraylistLinkedList)
14
- * [**补充内容:RandomAccess接口**](#:RandomAccess)
15
- * [补充内容:双向链表和双向循环链表](#:)
16
- * [1.3.2 ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?](#ArrayListVectorArraylistVector)
17
- * [1.3.3 说一说 ArrayList 的扩容机制吧](#ArrayList)
15
+ * [1.3.2 说一说 ArrayList 的扩容机制吧](#ArrayList)
18
16
* [ 1.4 Collection子接口之Set] ( #CollectionSet )
19
17
* [1.4.1 comparable 和 Comparator的区别](#comparableComparator)
20
18
* [Comparator定制排序](#Comparator)
21
19
* [重写compareTo方法实现按年龄来排序](#compareTo)
20
+ * [1.4.2 无序性和不可重复性的含义是什么](#1.4.2无序性和不可重复性的含义是什么)
21
+ * [1.4.3 比较HashSet 、LinkedHashSet和TreeSet三者的异同 ](#1.4.3比较HashSet、LinkedHashSet和TreeSet三者的异同 )
22
22
* [ 1.5 Map接口] ( #Map-1 )
23
23
* [1.5.1 HashMap 和 Hashtable 的区别](#HashMapHashtable)
24
24
* [1.5.2 HashMap 和 HashSet区别](#HashMapHashSet)
52
52
53
53
##### List
54
54
55
- - ** Arraylist:** Object数组
56
- - ** Vector:** Object数组
55
+ - ** Arraylist:** Object [ ] 数组
56
+ - ** Vector:** Object [ ] 数组
57
57
- ** LinkedList:** 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
58
58
59
59
##### Set
60
60
61
61
- ** HashSet(无序,唯一):** 基于 HashMap 实现的,底层采用 HashMap 来保存元素
62
- - ** LinkedHashSet:** LinkedHashSet 继承于 HashSet ,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的
62
+ - ** LinkedHashSet:** LinkedHashSet 是 HashSet的子类 ,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的
63
63
- ** TreeSet(有序,唯一):** 红黑树(自平衡的排序二叉树)
64
64
65
65
#### Map
81
81
但是集合提高了数据存储的灵活性,Java集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据
82
82
83
83
## 1.2 Iterator迭代器接口
84
+ ### 1.2.1 为什么要使用迭代器
85
+ Iterator对象称为迭代器(设计模式的一种),迭代器可以对集合进行遍历,但每一个集合内部的数据结构可能是不尽相同的,所以每一个集合存和取都很可能是不一样的,虽然我们可以人为地在每一个类中定义 hasNext() 和 next() 方法,但这样做会让整个集合体系过于臃肿。于是就有了迭代器。
84
86
85
- ## 1.3 Collection子接口之List
86
- ### 1.3.1 Arraylist 与 LinkedList 区别?
87
-
88
- - ** 1. 是否保证线程安全:** ` ArrayList ` 和 ` LinkedList ` 都是不同步的,也就是不保证线程安全;
89
-
90
- - ** 2. 底层数据结构:** ` Arraylist ` 底层使用的是 ** ` Object ` 数组** ;` LinkedList ` 底层使用的是 ** 双向链表** 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
91
-
92
- - ** 3. 插入和删除是否受元素位置的影响:** ① ** ` ArrayList ` 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。** 比如:执行` add(E e) ` 方法的时候, ` ArrayList ` 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(` add(int index, E element) ` )时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② ** ` LinkedList ` 采用链表存储,所以对于` add(E e) ` 方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置` i ` 插入和删除元素的话(` (add(int index, E element) ` ) 时间复杂度近似为` o(n)) ` 因为需要先移动到指定位置再插入。**
93
-
94
- - ** 4. 是否支持快速随机访问:** ` LinkedList ` 不支持高效的随机元素访问,而 ` ArrayList ` 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于` get(int index) ` 方法)。
95
-
96
- - ** 5. 内存空间占用:** ArrayList的空间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
97
-
98
- #### ** 补充内容: RandomAccess 接口**
99
-
100
- ``` java
101
- public interface RandomAccess {
102
- }
103
- ```
104
-
105
- 查看源码我们发现实际上 ` RandomAccess ` 接口中什么都没有定义。所以,在我看来 ` RandomAccess ` 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。
106
-
107
- 在 ` binarySearch() ` 方法中,它要判断传入的list 是否 ` RamdomAccess ` 的实例,如果是,调用` indexedBinarySearch() ` 方法,如果不是,那么调用` iteratorBinarySearch() ` 方法
108
-
109
- ``` java
110
- public static < T >
111
- int binarySearch(List<? extends Comparable<? super T > > list, T key) {
112
- if (list instanceof RandomAccess || list. size()< BINARYSEARCH_THRESHOLD )
113
- return Collections . indexedBinarySearch(list, key);
114
- else
115
- return Collections . iteratorBinarySearch(list, key);
116
- }
117
- ```
87
+ 迭代器是将这样的方法抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做就规定了整个集合体系的遍历方式都是hasNext()和next()方法,使用者不用管怎么实现的,会用即可。迭代器的定义为:提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。
118
88
119
- ` ArrayList ` 实现了 ` RandomAccess ` 接口, 而 ` LinkedList ` 没有实现。为什么呢?我觉得还是和底层数据结构有关!` ArrayList ` 底层是数组,而 ` LinkedList ` 底层是链表。数组天然支持随机访问,时间复杂度为 O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问。,` ArrayList ` 实现了 ` RandomAccess ` 接口,就表明了他具有快速随机访问功能。 ` RandomAccess ` 接口只是标识,并不是说 ` ArrayList ` 实现 ` RandomAccess ` 接口才具有快速随机访问功能的!
120
-
121
- ** 下面再总结一下 list 的遍历方式选择:**
89
+ ## 1.3 Collection子接口之List
90
+ ### 1.3.1 Arraylist、LinkedList与Vector的区别?
122
91
123
- - 实现了 ` RandomAccess ` 接口的list,优先选择普通 for 循环 ,其次 foreach,
124
- - 未实现 ` RandomAccess ` 接口的list,优先选择iterator遍历(foreach遍历底层也是通过iterator实现的),大size的数据,千万不要使用普通for循环
92
+ - ** 1. ArrayList是List的主要实现类,底层使用 Object[ ] 存储,适用于频繁的查找工作,线程不安全 ;
93
+ - ** 2. LinkedList是底层使用双向链表存储,适合频繁的增、删操作,线程不安全;
94
+ - ** 3. Vector是List的古老实现类,底层使用 Object[ ] 存储,线程安全的。
125
95
126
96
#### 补充内容:双向链表和双向循环链表
127
97
@@ -135,18 +105,12 @@ public interface RandomAccess {
135
105
136
106
![ 双向循环链表] ( https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/双向循环链表.png )
137
107
138
- ### 1.3.2 ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?
139
-
140
- ` Vector ` 类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
141
-
142
- ` Arraylist ` 不是同步的,所以在不需要保证线程安全时建议使用Arraylist。
143
-
144
- ### 1.3.3 说一说 ArrayList 的扩容机制吧
108
+ ### 1.3.2 说一说 ArrayList 的扩容机制吧
145
109
146
110
详见笔主的这篇文章:[ 通过源码一步一步分析ArrayList 扩容机制] ( https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/collection/ArrayList-Grow.md )
147
111
148
112
## 1.4 Collection子接口之Set
149
- ### 1.4.1 comparable 和 Comparator的区别
113
+ ### 1.4.1 comparable 和 Comparator的区别 r
150
114
151
115
- comparable接口实际上是出自java.lang包 它有一个 ` compareTo(Object obj) ` 方法用来排序
152
116
- comparator接口实际上是出自 java.util 包它有一个` compare(Object obj1, Object obj2) ` 方法用来排序
@@ -277,6 +241,19 @@ Output:
277
241
30-张三
278
242
```
279
243
244
+ ### 1.4.2 无序性和不可重复性的含义是什么
245
+ 1、什么是无序性?无序性不等于随机性 ,无序性是指存储的数据在底层数组中并非按照数组索引的顺序添加 ,而是根据数据的哈希值决定的。
246
+
247
+ 2、什么是不可重复性?不可重复性是指添加的元素按照equals()判断时 ,返回false,需要同时重写equals()方法和HashCode()方法。
248
+
249
+ ### 1.4.3 比较HashSet、LinkedHashSet和TreeSet三者的异同
250
+ HashSet是Set接口的主要实现类 ,HashSet的底层是HashMap,线程不安全的,可以存储null值;
251
+
252
+ LinkedHashSet是HashSet的子类,能够按照添加的顺序遍历;
253
+
254
+ TreeSet底层使用红黑树,能够按照添加元素的顺序进行遍历,排序的方式有自然排序和定制排序。
255
+
256
+
280
257
## 1.5 Map接口
281
258
### 1.5.1 HashMap 和 Hashtable 的区别
282
259
@@ -348,9 +325,11 @@ Output:
348
325
349
326
** ==与equals的区别**
350
327
351
- 1 . ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同
352
- 2 . ==是指对内存地址进行比较 equals()是对字符串的内容进行比较
353
- 3 . ==指引用是否相同 equals()指的是值是否相同
328
+ 对于基本类型来说,== 比较的是值是否相等;
329
+
330
+ 对于引用类型来说,== 比较的是两个引用是否指向同一个对象地址(两者在内存中存放的地址(堆内存地址)是否指向同一个地方);
331
+
332
+ 对于引用类型(包括包装类型)来说,equals 如果没有被重写,对比它们的地址是否相等;如果equals()方法被重写(例如String),则比较的是地址里的内容。
354
333
355
334
### 1.5.4 HashMap的底层实现
356
335
0 commit comments