HashMap
HashMap 是一個關聯數組、哈希表,它是線程不安全的,允許key爲null,value爲null。遍歷時無序。
其底層數據結構是數組稱之爲哈希桶,每個桶裏面放的是鏈表,鏈表中的每個節點,就是哈希表中的每個元素。
在JDK8中,當鏈表長度達到8,會轉化成紅黑樹,以提升它的查詢、插入效率,它實現了Map<K,V>, Cloneable, Serializable接口。
hashcode,equals , ==
capacity、loadFactor、threshold、size概念
DEFAULT_LOAD_FACTOR = 0.75f;
源碼
String中的hash()
public int hashCode() {
int h = hash;
if (h == 0 && count > 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
其中R = 31,
R 爲什麼等於31
- 31是一個不大不小的奇素數,(偶數的hash效果都比較差)
- 31 * i == (i << 5) - i ,可以被JVM優化
- 哈希分佈較爲均勻
擾動函數
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
擾動函數就是爲了解決hash碰撞的。它會綜合hash值高位和低位的特徵,並存放在低位,因此在與運算時,相當於高低位一起參與了運算,以減少hash碰撞的概率。(在JDK8之前,擾動函數會擾動四次,JDK8簡化了這個操作)
如何評價Hash算法好壞?
- 儘可能分佈均勻
- 效率儘可能快
MurMurHash
編譯原理中如何完美hash
實現hash衝突的方式
- 拉鍊法
- 鏈表
- 紅黑樹
- 探測法
擴容
爲什麼要用2的冪指數倍數
##實現一個自定義的class作爲HashMap的key該如何實現?
- 覆寫hashCode以及equals方法應該遵循的原則
- Immutable
hash攻擊
和hashtable 區別
- 與之相比HashTable是線程安全的,且不允許key、value是null。
- HashTable默認容量是11。
- HashTable是直接使用key的hashCode(key.hashCode())作爲hash值,不像HashMap內部使用static final int hash(Object key)擾動函數對key的hashCode進行擾動後作爲hash值。
- HashTable取哈希桶下標是直接用模運算%.(因爲其默認容量也不是2的n次方。所以也無法用位運算替代模運算)
- 擴容時,新容量是原來的2倍+1。int newCapacity = (oldCapacity << 1) + 1;
- Hashtable是Dictionary的子類同時也實現了Map接口,HashMap是Map接口的一個實現類;
和concurrentHashMap區別
https://www.jianshu.com/p/7af5bb1b57e2
https://blog.csdn.net/zxt0601/article/details/77413921