11.劍指JavaOffer-HashMap

經典問題:這三者的區別

image

HashMap的put的邏輯

image

閥值默認8,最低樹化容量:64

HashMap 的長度為什么是2的冪次方

Hash 值的范圍值-2147483648到2147483647,一個40億長度的數組,內存是放不下的,用之前還要先做對數組的長度取模運算,得到的余數才能用來要存放的位置也就是對應的數組下標。這個數組下標的計算方法是“ (n - 1) & hash”。(n代表數組長度)。這也就解釋了 HashMap 的長度為什么是2的冪次方。“取余(%)操作中如果除數是2的冪次則等價于與其除數減一的與(&)操作(也就是說 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。
length = 16 16 -1 = 15 15二進制 1111 再相與(&)hash效果很好

如何有效減少碰撞

  • 擾動函數:促使元素位置分布均勻,減少碰撞幾率(hash函數保證了同時包含高16位和低16位的特性,使得更加的不確定性)

  • 使用final對象,并采用合適的equals()和hashcode(),如String Integer ,因為hashcode不會變

追問,為什么若重寫equals(Object obj)方法,就必須重寫hashcode()方法,確保通過equals(Object obj)方法判斷結果為true的兩個對象具備相等的hashcode()返回值?

  • 如果重寫了equals(),兩個對象判斷相等了。但是沒有重寫hashCode(),有可能兩對象相等卻hashCode不同,則HashSet這種存唯一值的可能會存了兩個一樣的對象。

為什么使用HashCode?

  • 通過hashCode比較比equals方法快,當get時先比較hashCode,如果hashCode不同,直接返回false。

hash函數

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

圖示:


image.png

1.高16bt不變,低16bit和高16bit做了一個異或(得到的hashcode轉化為32位的二進制,前16位和后16位低16bit和高16bit做了一個異或)
2.(n-1)&hash=->得到下標

if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
image

HashMap也可以這樣寫實現線程安全:

Map safeHashMap = Collections.synchronizedMap(HashMap);

但是和Hashtable一樣,都是串行的,效率低下。

concurrentHashMap key和Value不可以為null

image

CAS樂觀鎖,synchronized悲觀鎖

image

concurrentHashMap 比java 8之前的 segment(分段加鎖),鎖更細

  • 首先使用無鎖操作CAS插入頭節點,失敗則循環重試

  • 若頭節點已存在,則嘗試獲取頭節點的同步鎖,再進行操作

size方法和mappingCount()方法的異同,兩者計算是否準確

JDK1.7 和 JDK1.8 對 size 的計算是不一樣的。 1.7 中是先不加鎖計算三次,如果三次結果不一樣在加鎖。

JDK1.8 size 是通過對 baseCount 和 counterCell 進行 CAS 計算,最終通過 baseCount 和 遍歷 CounterCell 數組得出 size。

JDK 8 推薦使用mappingCount 方法,因為這個方法的返回值是 long 類型,不會因為 size 方法是 int 類型限制最大值。

size()最大值是 Integer 類型的最大值,但是 Map 的 size 可能超過 MAX_VALUE, 所以還有一個方法 mappingCount(),JDK 的建議使用 mappingCount() 而不是size()

原文鏈接:https://blog.csdn.net/qq_27037443/article/details/94441885

多線程下環境如何進行擴容

HashMap擴容

concurrentHashMap擴容

TreeMap 是有序的散列表,它是通過紅黑樹實現的。它一般用于單線程中存儲有序的映射。(了解一下)

手撕一個Hashmap(無紅黑樹)

首先,接口類


public interface BtyMap<K,V> {

public V put(K k,V v);

public V get(K k);

  interface Entry<K,V>{

      public K getKey();

      public V getValue();

  }

}

具體實現類:

public class ButyHashMap<K,V> implements BtyMap<K, V>{

    private Entry<K, V>[] arr = null;

    int size;

    public ButyHashMap() {

        arr = new Entry[16];

    }

    public int size() {

        return this.size;

    }

    class Entry<K,V> implements BtyMap.Entry<K, V>{

        private K key;

        private V value;

        private Entry<K, V> next;

        public Entry(){

        }

        public Entry(K key, V value,Entry<K, V> next) {
            this.key = key;
            this.value = value;
            this.next=next;
        }

        @Override
        public K getKey(){return key;}

        @Override
        public V getValue(){return value;}

    }

    @Override
    public V put(K key, V value) {
        V oldValue= null;
        int index = key.hashCode() % arr.length;
        if (arr[index] == null) {
            arr[index] = new Entry<K,V>(key, value,null);
            size++;
        } else {
            Entry<K, V> entry=arr[index];
            Entry<K, V> e = entry;
            while(e != null){
                if(key == e.getKey()||key.equals(e.getValue())){
                    oldValue = e.value;
                    e.value = value;
                    return oldValue;
                }
                e = e.next;
            }
            arr[index] = new Entry(key, value, entry);
            size++;
        }
        return oldValue;
    }

    @Override
    public V get(K key){
        int index=key.hashCode() % arr.length;
        
        if(arr[index]==null)
            return null;
        else{
            Entry<K, V> entry = arr[index];
            while(entry!=null){
                if(key == entry.getKey()||key.equals(entry.getKey())){
                    return entry.value;
                }

                entry=entry.next;
            }
        }
        return null;
    }
}

紅黑樹規則

紅黑樹本質上還是二叉查找樹,額外的引入了5個約束條件:

1.節點只能是紅色或黑色

2.根節點必須是黑色

3.所有NIL節點都是黑色的

4.一條路徑上不能出現相鄰的兩個紅色節點

5.在任何遞歸子樹內,根節點到葉子節點的所有路徑上包含相同數目的黑色節點

紅黑樹的插入與旋轉
那些年,面試被虐過的紅黑樹

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,273評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,870評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,527評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,010評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,250評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,769評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,656評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,853評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,103評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,487評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,815評論 2 372

推薦閱讀更多精彩內容

  • HashMap全方位剖析 常見HashMap面試問答 HashMap是不是有序的? 不是有序的。 有沒有有序的Ma...
    從林戰士們閱讀 880評論 0 5
  • 轉自:卓慶森https://www.cnblogs.com/zhuoqingsen/p/8577646.html ...
    Java_xiaoman閱讀 6,198評論 0 5
  • 【同讀一本書劉姣】 2016-03-002-040 -《談話的力量》 【正文】 “身體接觸是無聲地告訴對方:...
    城市格調劉姣閱讀 418評論 1 1
  • ”我一直注意著哲學家,閱讀了他們的大量文字,此刻我暗自思量,大部分自覺的思維肯定屬于本能活動,就連哲學家的思維也是...
    魚1967閱讀 195評論 0 3
  • 從今天起,每天1個RIA便簽,堅持100天哦。 由《精進》開始,直面自己逃避已久的寫作問題。 當你處于人生中兩難抉...
    付曉閱讀 263評論 0 3