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原理:
下面這篇部落格講解了為什麼:物件的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除錯時在計算時很複雜,有很多輪迭代,暫時搞不懂原始碼咋跑的,不過上面的公式就是最終的結果。