HashMap 是一個關聯數組、哈希表,它是線程不安全的,允許key為null,value為null。遍歷時無序。
在JDK8中,當鏈表長度達到8,會轉化成紅黑樹,以提升它的查詢、插入效率,它實現了Map<K,V>, Cloneable, Serializable
接口。
因其底層哈希桶的數據結構是數組,所以也會涉及到擴容的問題。
當HashMap的容量達到threshold
域值時,就會觸發擴容。擴容前后,哈希桶的長度一定會是2的次方。
這樣在根據key的hash值尋找對應的哈希桶時,可以用位運算替代取余操作,更加高效。
數組: 內存中的一片連續區域,同類型數據的集合,有索引,查詢快,增刪慢,不可擴容。
鏈表: 不連續的區域,每個節點放值和指向下一個節點的指針。查詢慢,增刪快
哈希表: 可以理解位數組和鏈表的組合。即一個一維數組,但是數組中的每個元素是一個鏈表
HashMap常量:
1.DEFAULT_INITIAL_CAPACITY //默認初始化的容量時16,必須是2的冪次方。
2.MAXIMUM_CAPACITY //最大容量:最大的容量是2^30。
3.DEFAULT_LOAD_FACTOR = 0.75f //默認的負載因子是0.75
4.TREEIFY_THRESHOLD = 8 //一個桶中bin的存儲方式由鏈表轉換成樹的閾值。即當桶中bin的數量超過TREEIFY_THRESHOLD時使用樹來代替鏈表。默認值是8
5.UNTREEIFY_THRESHOLD = 6 //當執行resize擴容操作時,當桶中bin的數量少於UNTREEIFY_THRESHOLD時使用鏈表來代替樹。默認值是6 。
6.MIN_TREEIFY_CAPACITY //當桶中的bin被樹化時最小的hash表容量
成員變量:
1.transient Node<K,V>[] table; //這個數組在首次使用時初始化,並根據需要調整大小。分配空間時,長度始終是2的冪次方。
- table是一個用於存放鍵值對的數組。
- 第一次使用(插入元素)時被初始化,根據需要可以重新分配空間(擴容: 因為規定容量是2的冪,所以擴容時把原容量乘2.)。
- 分配的空間長度必須是2的冪次方。
2.transient Set<Map.Entry<K,V>> entrySet; //當被調用entrySet時被賦值。通過keySet()方法可以得到Map中的key集合,通過values可以得到Map中的value集合。
3.transient int size; //該值用於存放Map中鍵值對的個數。
4.transient int modCount; //HashMap被結構性修改的次數
5.int threshold; //閾值,當HashMap中的鍵值對數量超過了閾值,就會擴容。thresold = capacity * loadFactor
6.final float loadFactor; //負載因子
HashMap共包括4個構造函數:
public HashMap()// 默認構造函
public HashMap(int initialCapacity, float loadFactor) / /指定“容量大小”和“加載因子”的構造函數
public HashMap(int initialCapacity) // 指定“容量大小”的構造函數
public HashMap(Map<? extends K, ? extends V> m) // 包含“子Map”的構造函數,將m中的全部元素逐個添加到HashMap中
哈希沖突的解決方法:1.開放地址法 2.鏈地址法 3.公共溢出法 4.再哈希法
為什么HashMap線程不安全?
HashMap會進行resize操作,在resize操作的時候會造成線程不安全。
1. put的時候導致的多線程數據不一致
2. HashMap的get操作可能因為resize而引起死循環
HashMap線程不安全應該怎么解決?
1.使用HashTable替代HashMap //一個線程訪問HashTable的同步方法時,其他線程如果也要訪問同步方法,會被阻塞住。
2.類ConcurrentHashMap定義Map //ConcurrentHashMap是JUC包中的一個類,方法內部使用了synchronized保證線程安全。
3.Collections類的synchronizedMap(Map m)方法可以返回一個線程安全的Map
HashMap跟Hashtable的區別?
HashMap 是 Hashtable 的輕量級實現(非線程安全的實現),他們都完成了 Map 接口,主 要區別在於 HashMap 允許空(null)鍵值(key),由於非線程安全,在只有一個線程訪問 的情況下,效率要高於 Hashtable。
1.歷史原因:Hashtable 是基於陳舊的 Dictionary 類的,HashMap 是 Java 1.2引進的 Map 接口的一個實現
2.同步性:Hashtable 是線程安全的,也就是說是同步的,而 HashMap 是線程序不安全的, 不是同步的
3.值:只有 HashMap 可以讓你將空值作為一個表的條目的 key 或 value