1. 程式人生 > >hash和散列表在java中的作用

hash和散列表在java中的作用

散列表/雜湊表是儲存記錄的資料結構,雜湊函式是關鍵字和儲存位置的對應關係的對映函式,我們希望f(Key)得到不同雜湊地址。但是一般總會有衝突存在。key是關鍵字的話,是由字母數字組成的,大約1.2x10^14,而實際中用不到那麼多,雜湊函式就是一個壓縮映像。

Hash關鍵在於hash函式的選擇和衝突解決。
好的hash函式是均勻的,就是儘量不要對映後儲存位置聚集。

衝突解決當然很多,最常用的是開放定址法(包括三種探測再雜湊方法,就是微調一下雜湊函式,加一個步長di,重新找一個空位)和鏈地址法。

java的hashMap和hashTable就是使用鏈地址法。底層都是陣列加連結串列。他倆區別是hashTable是執行緒安全的。
hashcode不是返回真實地址,是虛擬機器對映的虛擬地址。key物件沒有重寫hashcode,value不會為null,重寫hashcode對應的是動態陣列中的值,hashcode不同直接就放陣列了,hashcode相同就把元素放入連結串列中,key物件相同就覆蓋value值。
有一篇部落格部分解釋了java中的hash和hashCode原理:

https://blog.csdn.net/qq_38182963/article/details/78940047
下面這篇部落格講解了為什麼:物件的equals方法被重寫,那麼物件的hashCode也儘量重寫。
https://blog.csdn.net/fenglibing/article/details/8905007

hashMap的部落格參考這篇解釋:
https://blog.csdn.net/ghsau/article/details/16843543

HashMap通過鍵的hashCode來快速的存取元素。
當不同的物件發生碰撞時,HashMap通過單鏈表來解決,將新元素加入連結串列表頭,通過next指向原有的元素。單鏈表在Java中的實現就是物件的引用(複合)。

下面我自己除錯了一下String計算hashcode的方法,因為hashMapo中一般key都是String型別嘛。

    @Test
    public void test(){
//        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//        CameraMapper mapper = ac.getBean(CameraMapper.class);
//        mapper.getCamByBingingFileId(1,4);
//        byte     1位元組
//        short    2位元組
//        int      4位元組
//        long     8位元組
//        char     2位元組(C語言中是1位元組)可以儲存一個漢字
//        float    4位元組
//        double   8位元組
//        boolean  false/true(理論上佔用1bit,1/8位元組,實際處理按1byte處理)


        String str1 = "1";
        String str2 = "a";
        String str3 = str1+"a";
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());
        System.out.println(str3.hashCode());
        char[] strChar=str3.toCharArray();
        String result="";
        for(int i=0;i<strChar.length;i++){
            result += Integer.toBinaryString(strChar[i])+ " ";
        }
        System.out.println(result);
    }



#結果:
49
97
1616
110001 1100001 

上面如果是單個字元,就是該字元的ASCII碼值,多個字元按 str[0]31^(n-1) + str31^(n-2) + … + str[n-1] 公式計算, 這裡str[i] 是第一個字元的ASCII碼值,可以根據這個手算預設hashcode值。

1616 = 97+49*31,完全正確。

debug除錯時在計算時很複雜,有很多輪迭代,暫時搞不懂原始碼咋跑的,不過上面的公式就是最終的結果。