Java集合(7):散列与散列码
? ? ? ?散列的價值在于速度。我們使用數組來保存鍵的信息,這個信息并不是鍵本身,而是通過鍵對象生成一個數字(散列碼),作為數組下標。由于數組的容量是固定的,而散列容器的大小是可變的,所以不同的鍵可以產生相同的數組下標(散列碼)。也就是說,可能會有沖突(當然也有特例,比如EnumMap和EnumSet)。所以,數組的值存放著一個保存所有相同散列碼的值的list(引用)。然后對list中的值使用equals進行線性查詢。如果散列函數設計的比較好的話,數組的每個位置只有較少的值,并且浪費空間也小。于是,查詢過程就是首先計算鍵的散列碼得到數組下標,然后內存尋址(時間復雜度為O(1),賦值)找到數組的值,再遍歷list(時間復雜度為O(n),線性查詢)即可。即hashCode和equals共同確定了對象的唯一性。
? ? ? ?所有類都繼承于Object。Object的hashCode方法生成的散列碼,實際上是默認使用對象的地址計算散列碼;而Object的equals方法實際上就是地址比較(==)。顯然,當我們在使用散列容器(如HashMap的Key,HashSet等)時,我們自定義的類中還繼承Object的hashCode和equals是不行的。必須重寫hashCode和equals方法。好的hashCode()應該產生分布均勻的散列碼。可以用IDE自動生成。下面是一個例子:
1 import java.util.List; 2 3 public class Test9 { 4 5 boolean a; 6 byte b; 7 short c; 8 int d; 9 char e; 10 long f; 11 float g; 12 double h; 13 String i; 14 List<String> j; 15 int[] k; 16 17 @Override 18 public int hashCode() { 19 // [STEP1] hashCode()里的魔法數字,之所以選擇31,是因為它是個奇素數,如果乘數是偶數,并且乘法溢出的話,信息就會丟失,因為與2相乘等價于移位運算。 20 // 使用素數的好處并不是很明顯,但是習慣上都使用素數來計算散列結果。31有個很好的特性,就是用移位和減法來代替乘法,可以得到更好的性能:31*i==(i<<5)-i。現在的VM可以自動完成這種優化。(from 《Effective Java》) 21 final int prime = 31; 22 // [STEP2] 為對象中每個有意義的域用下面公式計算散列碼 result = prime * result + c 23 int result = 1; 24 // boolean 25 result = prime * result + (a ? 1231 : 1237); 26 // byte/short/int/char 27 result = prime * result + b; 28 result = prime * result + c; 29 result = prime * result + d; 30 result = prime * result + e; 31 // long 32 result = prime * result + (int) (f ^ (f >>> 32)); 33 // float 34 result = prime * result + Float.floatToIntBits(g); 35 // double 36 long temp; 37 temp = Double.doubleToLongBits(h); 38 result = prime * result + (int) (temp ^ (temp >>> 32)); 39 // 對象 40 result = prime * result + ((i == null) ? 0 : i.hashCode()); 41 // List(要求每個元素實現hashCode) 42 result = prime * result + ((j == null) ? 0 : j.hashCode()); 43 // 數組(要求每個元素實現hashCode) 44 result = prime * result + Arrays.hashCode(k); 45 // [STEP3] 返回 46 return result; 47 } 48 @Override 49 public boolean equals(Object obj) { 50 if (this == obj) 51 return true; 52 if (obj == null) 53 return false; 54 if (getClass() != obj.getClass()) 55 return false; 56 Test9 other = (Test9) obj; 57 if (a != other.a) 58 return false; 59 if (b != other.b) 60 return false; 61 if (c != other.c) 62 return false; 63 if (d != other.d) 64 return false; 65 if (e != other.e) 66 return false; 67 if (f != other.f) 68 return false; 69 if (Float.floatToIntBits(g) != Float.floatToIntBits(other.g)) 70 return false; 71 if (Double.doubleToLongBits(h) != Double.doubleToLongBits(other.h)) 72 return false; 73 if (i == null) { 74 if (other.i != null) 75 return false; 76 } else if (!i.equals(other.i)) 77 return false; 78 if (j == null) { 79 if (other.j != null) 80 return false; 81 } else if (!j.equals(other.j)) 82 return false; 83 if (!Arrays.equals(k, other.k)) 84 return false; 85 return true; 86 } 87 }?
轉載于:https://www.cnblogs.com/storml/p/8550463.html
總結
以上是生活随笔為你收集整理的Java集合(7):散列与散列码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java调用公安接口_src 公安部PG
- 下一篇: 阿里Java开发手册(2021最新终极版