Writer:BYSocket(泥沙磚瓦漿木匠)java
微博:BYSocket程序員
豆瓣:BYSocket
web
泥瓦匠最近被項目搞的天昏地暗。發現有些要給本身一些目標,關於技術的目標:
算法
專一很重要。專一Java 基礎 + H5(學習)數據結構
其餘操做系統,算法,數據結構當成課外書博覽。有時候,就是那樣你越是專一方面越多對本身打擊越大學啥啥都很差。今天帶來Java基礎:hashCode方法socket
hash code(散列碼,也能夠叫哈希碼值)是對象產生的一個整型值。其生成沒有規律的。兩者散列碼能夠獲取對象中的信息,轉成那個對象的「相對惟一」的整型值。全部對象都有一個散列碼,hashCode()是根類 Object 的一個方法。散列表的工做原理在Java基礎不展開講,只要知道它是一種快速的「字典」便可。下面引用老外一張圖:函數
首先泥瓦匠引用一段來自 Object規範 【JavaSE6】:性能
hashCode的常規協定是:學習
一、在 Java 應用程序執行期間,在對同一對象屢次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。從某一應用程序的一次執行到同一應用程序的另外一次執行,該整數無需保持一致。優化
二、若是根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每一個對象調用
hashCode
方法都必須生成相同的整數結果。
三、若是根據equals方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法不 要求必定生成不一樣的整數結果。可是,程序員應該意識到,爲不相等的對象生成不一樣整數結果能夠提升哈希表的性能。
因爲hashCode定義在根類Object,因此每一個對象都是Object,都具備一個默認的散列值,便是對象的存儲地址。泥瓦匠請你們看一下這個例子:
public class HashCodeTest { public static void main(String[] args) { String s = "hashCode"; StringBuilder sb = new StringBuilder(s); System.out.println("hashCode1: " + s.hashCode() + " " + sb.hashCode()); String s1 = new String("hashCode"); StringBuilder sb1 = new StringBuilder(s1); System.out.println("hashCode2: " + s1.hashCode() + " " + sb1.hashCode()); // are they equals? System.out.println("s s1 : " + s.equals(s1)); System.out.println("sb sb1: " + sb.equals(sb1)); } }
run 一下,能夠在控制檯看到:
hashCode1: 147696667 1385112968 hashCode2: 147696667 870919696 s s1 : true sb sb1: false
泥瓦匠小結:
一、s 與 s1相等,且hashCode同樣。驗證了【hashCode的常規協定】的第二條。緣由是字符串的散列碼由內容導出的。(這個第二個例子咱們會驗證)
二、StringBuilder 裏面沒有定義hashCode方法,因此導出的是Object默認的對對象存儲的地址。(注意到Object的hashCode方法前面有個native的修飾符,這表示hashCode方法是由非java語言實現的,具體的方法實如今外部,返回內存對象的地址。)詳情請看認識&理解關鍵字 native 實戰篇。
泥瓦匠剛剛提到字符串散列碼是由內容導出的。下面看看String的hashCode的實現。
/** The value is used for character storage */private char value[]; private int hash;// Default to 0 /** * Returns a hash code for this string. The hash code for a * String object is computed as * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] */ public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
泥瓦匠小結:
一、s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1] 數學公式表明什麼?
s[i]是string的第i個字符,n是String的長度。31爲啥呢?下面引用《Effective Java》的原話:
之因此選擇31,是由於它是個奇素數,若是乘數是偶數,而且乘法溢出的話,信息就會丟失,由於與2相乘等價於移位運算。使用素數的好處並非很明顯,可是習慣上都使用素數來計算散列結果。31有個很好的特性,就是用移位和減法來代替乘法,能夠獲得更好的性能:31*i==(i<<5)-i。如今的VM能夠自動完成這種優化。
確實hashCode有點晦澀,有多是由於那個數學散列函數。下面是《Effective Java》中的結論點:
一、若是對象有相同的散列碼,被映射到同一個散列桶,這樣散列表退化稱爲 鏈表 ,這樣性能下降。
二、相等的對象必須具備相等的散列碼
三、爲不相等的對象產生不相等的散列碼
四、不要試圖從散列碼計算中排除掉一個對象關鍵部分來提升性能
Writer:BYSocket(泥沙磚瓦漿木匠)
微博:BYSocket
豆瓣:BYSocket