Java 集合學習筆記
阿新 • • 發佈:2021-02-21
@[TOC]
# Java 集合(容器)
## 一、Java 集合框架概述
* 一方面,面嚮物件語言對事務的體現都是以物件的形式,為了方便對多個物件的操作,就要對物件進行儲存。另一方面,使用 Array 儲存物件放面具有一些弊端,而 Java 集合就像一種容器,可以動態的把多個物件的引用放入容器中。
* 陣列在記憶體儲存方面的特點:
* 陣列初始化以後,長度就確定了
* 陣列宣告的型別,就決定了元素初始化時的型別
* 陣列在儲存資料方面的弊端:
* 陣列初始化以後,長度不可變,不便於擴充套件
* 陣列中提供的屬性和方法少,不便於進行新增、刪除、插入等操作,且效率不高。同時無法直接獲取儲存的元素的個數
* 陣列儲存的資料是有序的、可重複的。(儲存資料的特點單一)
* Java 集合類可用於儲存數量不等的多個物件,還可用於儲存具有對映關係的關聯陣列。
* Java 集合可分為 Collection 和 Map 兩種體系
* Collection 介面:單列資料,定義了存取一組物件的方法和集合
* List:元素有序、可重複的集合
* Set:元素無需、不可重複的集合
* Map 集合:雙列資料,儲存具有對映關係 “ key - value 對” 的集合
* Collection 介面繼承樹
![Collection 介面繼承樹](https://img-blog.csdnimg.cn/20191124102651811.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3o3MTA3NTcyOTM=,size_16,color_FFFFFF,t_70)
* Map 介面繼承樹
![介面繼承樹](https://img-blog.csdnimg.cn/20191124102742432.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3o3MTA3NTcyOTM=,size_16,color_FFFFFF,t_70)
## 二、Collection 介面方法
[Collection 介面中文文件(JDK 11)](https://www.runoob.com/manual/jdk11api/java.base/java/util/Collection.html)
1. 新增
* add(Object obj)
* addAll(Collection coll):將集合 coll 中的所有元素新增到當前集合中
2. 獲取有效元素的個數
* int size()
3. 清空合集
* void clear()
4. 是否為空集合
* boolean isEmpty()
5. 是否包含某個元素
* boolean contains(Object obj):是通過**元素的 equals 方法**來判斷是否是同一個物件
* boolean containsAll(Collection c):也是呼叫 equals 方法來比較,用兩個集合的元素挨個比較。
6. 刪除
* boolean remove(Object obj):通過 equals 方法定位,並刪除,**只會刪除找到的第一個元素**
* boolean removeAll(Collection coll):取當前集合的差集
7. 取兩個集合的交集
* boolean retainAll(Collection c):把交集的結果存在當前集合中,不影響集合 c
8. 集合是否相等
* boolean equals(Object obj)
9. 轉成物件陣列
* Object[] toArray()
* 陣列 轉化成 集合:呼叫 Arrays 類的靜態方法 asList()。
* 但要注意該方法直接寫入 new int[](123, 456) 只是把整體當成一個元素存入,此時用包裝類的方式即可解決。
10. 獲取集合物件的雜湊值
* hashCode()
11. 遍歷
* iterator():返回迭代器物件,用於遍歷集合
## 三、Iterator 迭代器介面
### 1. 使用 Iterator 介面遍歷集合元素
* Iterator 物件稱為迭代器(設計模式的一種),主要用於遍歷 Collection 集合中的元素。
* GOF 給迭代器模式的定義為:提供一種方法訪問一個容器(container)物件中各個元素,而又不需要暴露該物件的內部細節。迭代器模式,便是為容器而生。類似於”公交車上的售票員”、”火車上的乘務員“、”空姐“。
* Collection 介面繼承了 java.lang.Iterator 介面,該介面有一個 Iterator() 方法,那麼所有實現了 Collection 介面的集合類都有一個 Iterator() 方法,用以返回一個實現了 Iterator 介面的物件。
### 2. Iterator 介面的方法
| boolean | hasNext(): Return true if the iterator has more elements. |
| ------- | ------------------------------------------------------------ |
| E | next(): Return the next element int the iteration. |
| void | remove(): Removes from the underlying collection the last element returned by the iterator(optional operation). |
* 可採取 hasNext() 和 next() 方法配合遍歷集合
==在呼叫it.next()方法之前必須要呼叫it.hasNext()進行檢測。若不呼叫,且下一條記錄無效,直接呼叫it.next()會丟擲NoSuchElementException異常。==
```java
while(iterator.hasNext) {
iterator.next();
}
```
**兩種常見的錯誤遍歷方式:**
```java
//方式一:
Iterator iterator = coll.iterator();
while(iterator.next() != null) {
System.out.println(iterator.next());
}
//while的條件會使 集合指標 移動一次,導致輸出結果跳躍
```
```java
//方式二:
while(coll.iterator().hasNext()) {
System.out.println(coll.iterator().next());
}
//集合物件每次呼叫 iterator() 方法都會得到一個全新的迭代器物件,預設指標 都會從集合的第一個元素開始。
```
* 有關 remove()
```java
Iterator iter = coll.iterator();
while(iter.hasNext()) {
Object obj = iter.next();
if(obj,equals("Tom")) {
iter.remove();
}
}
```
* 注意
* Iterator 可以刪除集合的元素,但是 是通過遍歷過程中通過迭代器物件的 remove 方法,不是集合物件的 remove 方法。
* 如果還未呼叫 next() 或在上一次呼叫 next 方法之後已經呼叫了 remove 方法,再呼叫 remove 都會報IllegalStateException
### 3. 使用 foreach 迴圈遍歷集合元素
* Java 5.0 提供了 foreach 迴圈迭代訪問 Collection 和 陣列
* 遍歷操作不需要獲取 Collection 或陣列的長度,無需使用索引訪問元素
* 遍歷集合和底層呼叫 Iterator 完成操作
* foreach 還可以用來遍歷陣列
![](https://img-blog.csdnimg.cn/20210221113140194.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
## 四、Collection 子介面一:List
### 1. List 介面概述
* 鑑於 Java 中陣列用來儲存資料的侷限性,我們通常使用List替代陣列
* List 集合類中 元素有序、且可重複,集合中的每個元素都有其對應的順序索引。
* List容器中的元素都對應一個整數型的序號記載其在容器中的位置,可以根據序號存取容器中的元素。
* JDK API中List介面的實現類常用的有:ArrayList、LinkedList和Vector。
### 2. List 介面方法
* List 除了從 Collection 集合繼承的方法外,List 集合裡添加了一些根據索引來操作集合元素的方法。
* void add(int index, Object ele):在 index 位置插入 ele 元素
* boolean addAll(int index, Collection eles):從 index 位置開始將 eles 中的所有元素新增進來
* Object get(int index):獲取指定 index 位置的元素
* int indexOf(Object obj):返回 obj 在集合中首次出現的位置
* int lastIndexOf(Object obj):返回 obj 在當前集合中末次出現的位置
* Object remove(int index):移除指定 index 位置的元素,並返回此元素
* Object set(int index, Object ele):設定指定 index 位置的元素為 ele
* List subList(int fromIndex, int toIndex):返回從 fromIndex 到 toIndex 位置的子集合
### 3. List 實現類之一:ArrayList(主要)
* ArrayList 是 List 介面的典型實現類、主要實現類
* 本質上,ArrayList 是物件引用的一個“變長“陣列
* ArrayList 的 JDK 1.8 之前與之後的 空參構造器 的實現區別(其他方面無異)?
* JDK 1.7:類似餓漢式,直接建立一個初始容量為 10 的陣列
* ```java
ArrayList list = new ArrayList();
list.add(123); // elementData[0] = new Integer(123);
```
* 當陣列 elementData 陣列容量不夠時,預設情況下,擴容為原來的 1.5 倍,同時將原來陣列中的資料複製到新的陣列中。
* 建議開發中使用帶參構造器:一開始人為的確定容量
* JDK 1.8:類似懶漢式,一開始建立一個長度為 0 的陣列,當新增第一個元素時再建立一個是容量為 10 的陣列
* Array.asList() 方法返回的 List 集合,既不是ArrayList 試裡,也不是 Vector 例項。Array.asList() 返回值是一個固定長度的 List 集合。
* [**原始碼分析傳送門** ](https://someoneiscoding.com/2019/04/03/about_ArrayList/)(轉載)
### 4. List 實現類之二:LinkedList
* 適合頻繁的插入或刪除元素的操作,效率較高
* 雙向連結串列
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221113211700.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
### 5. List 實現類之三:Vector
* Vector 很古老,JDK 1.0 就有了。大多數操作與 ArrayList 相同,區別在於 Vector 是執行緒安全的,但效率總是比 ArrayList 慢,一般不用。
### 6. List 三種實現類的異同
1. ArrayList 與 LinkedList 區別:(參考javaGuide)
1. **是否執行緒安全**:二者執行緒不完全,相對執行緒安全的 Vector,執行效率更高
2. **底層資料結構**:ArrayList 和Vector 實現了基於動態陣列的資料結構,LinkedList是基於連結串列的資料結構(JDK1.6之前為迴圈連結串列,JDK1.7取消了迴圈)。
3. **插入和刪除元素**:
* 對於 ArrayList ,由於是陣列結構,故在指定位置 i 插入或刪除元素的畫,時間複雜度為 O(n-i) ,即操作位置之後的所有元素後移或前移。
* 對於 LinkedList ,由於採用連結串列結構,插入刪除元素的時間複雜度近似為 O(1) , 若在指定位置插入元素,時間複雜度近似為 O(n) ,因為要先移動到指定位置,再進行操作。
4. **是否支援快速隨機訪問:**LinkedList 不支援高效的隨即元素訪問,而 ArrayList 支援。快速隨機訪問就是通過元素的序號開速獲取元素物件。
5. **記憶體空間佔用:**ArrayList 的空間浪費主要體現在 list 列表的結尾會預留一定的容量空間,而 LinkedList 的空間花費則體現在它的每一個元素都需要消耗比 ArrayList 更多的空間(因為要存放直接後繼和直接前驅以及資料)。
2. ArrayList 和 Vector 的區別
Vector 和 ArrayList 幾乎完全相同,最大區別為 Vector 是同步類(synchronized),屬於強同步類。因此開銷比 ArrayList 要大,訪問要慢。正常情況下,一般使用 ArrayList 而不是 Vector,因為同步完全可以由程式設計師自己來控制(如使用Collections的方法)。
Vector 每次擴容請求其大小的 2 倍空間,而 ArrayList 是 1.5 倍。
Vector還有一個子類 Stack ## 五、Collection 子介面二:Set ### 1. Set 介面概述 * Set 介面是 Collection 的子介面,Set 介面沒有提供額外的方法。 * Set 集合不允許包含相同的元素 * Set 判斷兩個物件是否相同,使用的是 equals() 方法。 ### 2. Set 實現類之一:HashSet * HashSet 是 Set 介面的典型實現,大多數使用 Set 集合時都使用該實現類。 * HashSet 按 Hash 演算法來儲存集合種的元素,因此具有很好的存取、查詢、刪除效能。 * **HashSet 具有以下特點:** * 不能保證元素的排列順序 * HashSet 不是執行緒同步的 * 集合元素可以時null * **HashSet 集合判斷兩個元素相等的標準:** 通過 hashCode() 方法比較相等,並且兩個物件的 equals() 方法返回值也相等。 * 對於存放在 Set 容器種的物件,對應的類一定要重寫 equals() 和 hashCode(Object obj) 方法,以實現物件相等規則。即:”相等的物件必須具有相等的雜湊碼“。 * HashSet新增元素的過程: 新增元素a,首先呼叫元素 a 所在類的 hashcode() 方法,計算元素a的雜湊值,通過此雜湊值和某種雜湊函式 計算出在 HashSet 底層陣列的存放位置(即為:索引位置),判斷此位置上是否已經又元素:
如果此位置上沒有其他元素,則元素 a 新增成功(情況1)
如果此位置上有其他元素 b (或以連結串列形式存在的多個元素), 則比較元素 a 與元素 b 的雜湊值:
若雜湊值不同:則元素 a 新增成功(情況2)
若雜湊值相同:需要呼叫元素 a 所在類的 equals() 方法
equals() 返回 true :新增失敗
equals() 返回 false:新增成功(情況3)
* 對於新增成功的 情況2 和 情況3 而言:元素 a 與已經存在指定索引位置上資料以連結串列的方式儲存。
* jdk 7 :元素 a 放到陣列中,指向原來的元素
* jdk 8 :原來的元素在陣列中,指向元素 a
(七上八下)
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221113242848.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
> 底層也是陣列,初始容量為16,當如果使用率超過0.75(16*0.75=12)就會擴大容量為原來的2倍。(16擴容為32,依次為64,128....等)
* 上述提到的雜湊函式,會與底層陣列的長度相計算得到在陣列中的下標,並且這種雜湊函式計算還儘可能保證能均勻儲存元素,越是雜湊分佈,該雜湊函式設計的越好。
* **重寫 hashCode() 方法的基本原則**
* 在程式執行時,同時一個物件多次呼叫 hashCode() 方法應該返回相同的值。
* 當兩個物件的 equals() 方法比較返回 true 時,這兩個物件的 hashCode() 方法的返回值也相等
* 物件中作用 equals() 方法比較的 Field,都應該用來計算 hashCode 值
* **重寫 equals() 方法的基本原則**
* 當一個類有自己獨特的 “邏輯相等” 概念,當該重寫 equals() 的時候,總要重寫 hashCode() ,根據一個類的 equals 方法(重寫後),兩個截然不同的例項有可能在邏輯上時相等的,但是根據 Object.hashCode() 方法,它們僅僅是兩個物件。
* 因此,違反了 “相等的物件必須具有相等的雜湊碼”。
* 結論:重寫 equals 方法的時候一般都需要同時重寫 hashCode 方法,通常參與計算 hashCode 的物件的屬性也應該參與到 equals() 中進行計算。
* 為什麼用 Eclipse/IDEA 重寫的 hashCode 方法,有31這個數字?
* 選擇係數的時候要儘量選擇最大的係數,因為如果計算出來的 hash 地址越大,所謂的“衝突”就越少。查詢起來效率也會提高(減少衝突)
* 31 只佔用 5 bits,相乘造成資料溢位的概率較小
* 31 可以由 i * 31 == (i << 5) - 1,現在很多虛擬機器裡面都有相關優化。(提高演算法效率)
* 31 是一個素數,某個數與素數相乘,結果只能被該素數,和被乘數還有 1 來整除(減少衝突)
### 3. Set 實現類之二:LinkedHashSet
* LinkedHashSet 是 HashSet 的子類
* LinkedHashSet 根據元素的 hashCode 值來決定元素的儲存位置,但它同時使用雙向連結串列維護元素的次序,這使得元素看起來是以插入順序儲存的
* LinkedHashSet 插入效能略低於 HashSet,但在迭代訪問 Set 裡的全部元素時有更好的效能
* LinkedHashSet 不允許集合元素重複
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/2021022111334817.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
### 4. Set 實現類之三:TreeSet
* TreeSet 時 SortedSet 介面的實現類,TreeSet 可以確保集合元素處於排序狀態。
* TreeSet 底層使用 紅黑樹 結構儲存資料
* TreeSet 兩種排序方法:自然排序和定製排序。預設情況下,TreeSet 採用自然排序。
* 自然排序:
* 向 TreeSet 中新增元素時,只有第一個元素無須比較 compareTo() 方法,後面新增的元素都會呼叫 compareTo() 方法進行比較。
* 因為只有相同類的兩個例項才會比較大小,所以向 TreeSet 中新增的應該時同一個類的物件。
* 對於 TreeSet 集合而言,它判斷兩個物件是否相等的唯一標準是:兩個物件通過 compareTo(Object obj) 方法比較返回值
* 當需要把一個物件放入 TreeSet 中,重寫該物件對應的 equals 方法時,應保證該方法與 compareTo(Object obj) 方法有一致的結果:如果兩個物件通過 equals() 方法比較返回 true,則通過 compareTo(Object obj) 方法比較 應返回 0 ,否則可讀性較差。
* 定製排序:
* TreeSet 的自然排序要求元素所屬的類實現 Comparable 介面,如果元素所屬的類沒有實現 Comparable 介面,或不希望按照升序(預設情況)的方式排列元素或希望按照其他屬性大小進行排序,則考慮使用定製排序。定製排序,通過 Comparator 介面來實現。需要重寫 compae(T o1, T o2) 方法。
* 利用 int compare(T o1, T o2) 方法, 比較 o1 和 o2 的大小:如果方法返回正整數,則表示 o1 大於 o2;如果返回 0,表示相等;返回負整數,表示 o1 小於 o2。
* 要實現定製排序,需要將實現 Comparator 介面的例項作為引數傳遞給 TreeSet 的構造器
* 此時,仍然只能向 TreeSet 中新增型別相同的物件。否則發生 ClassCastException 異常。
* 使用定製排序判斷兩個元素相等的標準是:通過 Comparator 比較兩個元素返回了 0。
## 六、Map 介面
### 1. Map 介面概述
* Map 與 Collection 並列存在。用於儲存具有對映關係的資料: key - value
* Map 中的 key 和 value 都可以是任何引用型別的資料
* Map 中的 key 用 Set 來存放,**不允許重複**,即同一個 Map 物件所對應的類,必須重寫 hashCode() 和 equals() 方法
* 常用 String 類作為 Map 的 ”鍵“
* key 和 value 之間存在單向一對一關係,即通過指定的 key 總能找到唯一的、確定的 value
* Map 介面的常用實現類:HashMap、TreeMap、LinkedHashMap 和 Properties。其中,HashMap 是 Map 介面使用頻率最高的實現類。
* **Map結構的理解:**
* Map 中的 key 無序的、不可重複的,使用 Set 儲存所有的 key (key 所在類要重寫 equals() 和 hashCode() )
* Map 中的 value:無序的、可重複的,使用 Collection 儲存所有的 value (value 所在的類要重寫 equals() )
* 一個鍵值對:key - value 構成了一個 Entry 物件。
* Map 中的 Entry :無序的、不可重複的,使用 Set 儲存所有的 Entry。
* ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221113510844.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
* Map 介面常用方法:
* ![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20210221113528143.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQwNDYzMTE3,size_16,color_FFFFFF,t_70)
### 2. Map 實現類之一:HashMap
1. **Some Tips**
* HashMap 是 Map介面使用頻率最高的實現類
* 允許使用 null 鍵和 null 值,與 Hash Set 一樣
* 所有的 key 構成的集合是 Set :無序的、不可重複的。所以,key 所在的類要重寫 equals() 和 hashCode()
* 所有的 value 構成的集合是 Collection:無序的、可以重複的。所以,value所在類要重寫 equals()
* 一個 key-value 構成一個 entry
* 所有的 entry 構成的集合是 Set:無需的、不可重複的
* HashMap 判斷兩個 key 相等的標準是:兩個 key 通過 equals() 返回 true
* HashMap 判斷兩個 value 相等的標準是:兩個 value 通過 equals() 返回 true
2. JDK 7 及以前
1. **新增元素的過程**(jdk7)
`HashMap map = new HashMap();`
在例項化後,底層建立了長度為 16 的一維陣列 Entry[] table
(可能已經執行多次 put )
`map.put(key1, value1);`
首先,呼叫 key1 所在類的 hashCode() 計算 key1 雜湊值,此雜湊值經過某種演算法計算後,得到在 Entry 陣列中存放的位置
如果此位置上的資料為空,此時的 key1-value1 新增成功(情況1)
如果此位置上的資料不為空,(意味著此位置上存在一個或多個數據(以連結串列形式存在)),比較 key1 和已經存在的一個或多個數據的雜湊值:
如果 key1 的雜湊值與已經存在的資料的雜湊值都不相同,key1-value1 新增成功(情況2)
如果 key1 的雜湊值和已經存在的某一個數據(key2-value2)的雜湊值相同,就繼續比較:呼叫 key1 所在類的 equals(key2):
如果 equals() 返回 false:key1-value1新增成功。(情況3)
如果 equals() 返回 true:使用 value1 替換 value2
* **(情況 2 與情況 3 :key1-value1 和原來的資料以連結串列的形式儲存) **
* 擴容(resize):**轉移到新的**容量為原來的**兩倍**的陣列中。
2. **擴容時機**
當 HashMap 中的元素個數超過陣列大小(陣列總大小length,不是陣列中個數 size ) * loadFactor 時 , 就會 進行陣列擴容, loadFactor 的預設值( DEFAULT_LOAD_FACTOR)為 0.75,這是一個折中的取值。也就是說,預設情況下,陣列大小(DEFAULT_INITIAL_CAPACITY)為 16,那麼當 HashMap 中元素個數超過16 * 0.75=12(這個值就是程式碼中的 threshold 值,也叫做臨界值)的時候,就把陣列的大小擴充套件為2*16=32,即擴大一倍,然後重新計算每個元素在陣列中的位置,而這是一個非常消耗效能的操作,所以如果我們已經預知 HashMap 中元素的個數,那麼預設元素的個數能夠有效的提高 HashMap 的效能。
3. jdk 8 與jdk 7 的區別
1. new HashMap() 時:底層沒有建立一個長度為 16 的陣列
2. 首次呼叫 put() 方法時,底層建立長度為 16 的陣列
3. Entry() 改為 Node[]
4. JDK 8 形成連結串列結構時,新新增的 key - value 對在連結串列的尾部 (7 上 8 下 )
5. jdk 7 底層結構只有:陣列 + 連結串列
**jdk 8 底層結構:陣列 + 連結串列 + 紅黑樹**
當陣列的某一個索引位置上的元素以連結串列形式存在的資料個數 > 8 且當前這個陣列的長度超過 64 時,這個鏈會變成樹,結點型別由 Node 變成 TreeNode 型別。當然,如果當對映關係被移除後,下次 resize 方法時判斷樹的結點個數低於6個,也會把樹再轉為連結串列。
4. 部分主要常量
* **DEFAULT_INITIAL_CAPACITY** : HashMap的預設容量,16
* MAXIMUM_CAPACITY : HashMap的最大支援容量,2^30
* **DEFAULT_LOAD_FACTOR** :HashMap的預設載入因子:0.75
* **TREEIFY_THRESHOLD **:Bucket中連結串列長度大於該預設值,轉化為紅黑樹(8)
* UNTREEIFY_THRESHOLD :Bucket中紅黑樹儲存的Node小於該預設值,轉化為連結串列
* **MIN_TREEIFY_CAPACITY** :桶中的Node被樹化時最小的hash表容量(64)。(當桶中Node的數量大到需要變紅黑樹時,若hash表容量小於MIN_TREEIFY_CAPACITY時,此時應執行resize擴容操作這個MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4倍。)
* table :儲存元素的陣列,總是2的n次冪
* entrySet: :儲存具體元素的集
* size :HashMap中儲存的鍵值對的數量
* modCount :HashMap擴容和結構改變的次數。
* **threshold** :**擴容的臨界值 = 容量 * 填充因子 :16 * 0.75 = 12**
* **提前擴容,可以讓連結串列少一些**
* loadFactor: :填充因子
5. **LoadFactor(負載因子值、 填充因子值、填充比)的大小,對 HashMap的影響**
* 決定 HashMap 的資料密度
* LoadFactor 越大密度越大,發生碰撞的機率越高,陣列中的連結串列越容易長,造成查詢或插入時的比較次數增多,效能下降
* LoadFactor 越小,越容易觸發擴容,資料密度也越小,碰撞機率越小,陣列中的連結串列也越短,查詢和插入時比較的次數也越小,效能會較高。但是會浪費更多的記憶體。而且經常擴容也會影響效能,故建議初始化預設大一點的空間。
* 設定為 0.7 ~ 0.75 較為常規:此時平均檢索長度接近於常數。
### 3. Map 實現類之二:LinkedHashMap
* 是 HashMap 的子類
* 在 HashMap 儲存結構的基礎上,使用了一對雙向連結串列來記錄新增元素的順序。
* 與 LinkedHashSet 類似,其可以維護 Map 的迭代順序:迭代順序與 Key-Value 對的插入順序一致。
* HashMap 中的內部類:Node
```java
static cl
Vector 和 ArrayList 幾乎完全相同,最大區別為 Vector 是同步類(synchronized),屬於強同步類。因此開銷比 ArrayList 要大,訪問要慢。正常情況下,一般使用 ArrayList 而不是 Vector,因為同步完全可以由程式設計師自己來控制(如使用Collections的方法)。
Vector 每次擴容請求其大小的 2 倍空間,而 ArrayList 是 1.5 倍。
Vector還有一個子類 Stack ## 五、Collection 子介面二:Set ### 1. Set 介面概述 * Set 介面是 Collection 的子介面,Set 介面沒有提供額外的方法。 * Set 集合不允許包含相同的元素 * Set 判斷兩個物件是否相同,使用的是 equals() 方法。 ### 2. Set 實現類之一:HashSet * HashSet 是 Set 介面的典型實現,大多數使用 Set 集合時都使用該實現類。 * HashSet 按 Hash 演算法來儲存集合種的元素,因此具有很好的存取、查詢、刪除效能。 * **HashSet 具有以下特點:** * 不能保證元素的排列順序 * HashSet 不是執行緒同步的 * 集合元素可以時null * **HashSet 集合判斷兩個元素相等的標準:** 通過 hashCode() 方法比較相等,並且兩個物件的 equals() 方法返回值也相等。 * 對於存放在 Set 容器種的物件,對應的類一定要重寫 equals() 和 hashCode(Object obj) 方法,以實現物件相等規則。即:”相等的物件必須具有相等的雜湊碼“。 * HashSet新增元素的過程: 新增元素a,首先呼叫元素 a 所在類的 hashcode() 方法,計算元素a的雜湊值,通過此雜湊值和某種雜湊函式