Java 面試題 HashMap、ConcurrentHashMap、HashTable

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;
}

h=Rh+val[off++] h = R * h + val[off++]
其中R = 31,
R 爲什麼等於31

  1. 31是一個不大不小的奇素數,(偶數的hash效果都比較差)
  2. 31 * i == (i << 5) - i ,可以被JVM優化
  3. 哈希分佈較爲均勻

擾動函數

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

擾動函數就是爲了解決hash碰撞的。它會綜合hash值高位和低位的特徵,並存放在低位,因此在與運算時,相當於高低位一起參與了運算,以減少hash碰撞的概率。(在JDK8之前,擾動函數會擾動四次,JDK8簡化了這個操作)

如何評價Hash算法好壞?

  1. 儘可能分佈均勻
  2. 效率儘可能快

MurMurHash

編譯原理中如何完美hash

實現hash衝突的方式

  1. 拉鍊法
    1. 鏈表
    2. 紅黑樹
  2. 探測法

擴容

爲什麼要用2的冪指數倍數

##實現一個自定義的class作爲HashMap的key該如何實現?

  1. 覆寫hashCode以及equals方法應該遵循的原則
  2. Immutable

hash攻擊

和hashtable 區別

  1. 與之相比HashTable是線程安全的,且不允許key、value是null。
  2. HashTable默認容量是11。
  3. HashTable是直接使用key的hashCode(key.hashCode())作爲hash值,不像HashMap內部使用static final int hash(Object key)擾動函數對key的hashCode進行擾動後作爲hash值。
  4. HashTable取哈希桶下標是直接用模運算%.(因爲其默認容量也不是2的n次方。所以也無法用位運算替代模運算)
  5. 擴容時,新容量是原來的2倍+1。int newCapacity = (oldCapacity << 1) + 1;
  6. Hashtable是Dictionary的子類同時也實現了Map接口,HashMap是Map接口的一個實現類;

和concurrentHashMap區別

https://www.jianshu.com/p/7af5bb1b57e2
https://blog.csdn.net/zxt0601/article/details/77413921

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章