在比較兩個實例是否相等的時候,一般會覆寫equal()方法,而後對類對象的每一成員進行逐一比較,可是JavaSE6規範以下:java
應用程序的執行期間,只要對象的equals方法的比較操做所用到的信息沒有被修改,那麼對這同一個對象調用屢次,hashCode方法都必須始終如一地返回同一個整數。在同一個應用程序的屢次執行過程當中,每次執行所返回的整數能夠不一致。數組
若是兩個對象根據equals()方法比較是相等的,那麼調用這兩個對象中任意一個對象的hashCode方法都必須產生一樣的整數結果。ide
若是調用父類的equal()
方法,且x.equal(y)
返回值是true,返回的hashCode值卻不一樣,所以在覆寫equal()方法的同時覆寫hashCode()
方法。這樣才能最大限度地保證,在程序運行過程當中儘量少的出現莫名其妙的錯誤。函數
再此以前咱們先看一下String
類中的hashCode()方法:學習
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; }
你們可能會以爲莫名其妙,hashCode()方法返回的是一個int類型的值,難道這就是所謂的hashCode?不要急,咱們來看一段話,code
一個好的散列函數一般傾向於「爲不相等的對象產生不相等的散列碼」
對於對象中的每一個關鍵域f(指equal方法中涉及的每一個域),完成如下步驟:對象
若是該域是boolean類型,則計算
(f?1:0)
;遞歸若是該域是byte、char、short或者int計算
(int)f
;字符串若是該域是long型,計算
(int)(f^(f>>>32))
;get若是該域是float類型,計算
Float.floatTOIntBits(f)
;若是該域是double類型,計算
Double.doubleToLongBits(f)
,而後再根據long型計算獲得散列值;若是該域是一個引用對象,而且該類的equal方法經過遞歸調用equal的方法來比較這個域,則一樣爲這個域遞歸調用hashCode,若是這個域爲空,則返回0;
-若是該域是一個數組,則要把每個元素看成單獨的域來處理按照下面的公式,把上面計算獲得的散列碼c合併到result中
result=31*result+c
;
--------------摘自Effective Java
這是EffectiveJava中給出的計算散列碼的方法,固然,方法並非惟一,只要咱們保證相同的對象會產生相同的散列碼,不一樣的得到的散列碼不一樣就能夠了。
如今咱們回過頭來看看String
類中的hashCode方法
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) {//判斷hash值不爲0,字符串不爲空(即長度大於0) char val[] = value;//將字符串的值轉化爲char型數組 for (int i = 0; i < value.length; i++) { h = 31 * h + val[i];//遍歷char數組中的每個元素經過計算獲得hash值 } hash = h; } return h; }
看到這裏相信你們已經明瞭,hash散列碼的意義所在,
這裏咱們給出一段三個域都是int
的hash值計算實例
@Override public int hashCode() { int result = hashCode; //生成對象的惟一散列碼 if (result == 0) { result = result * 31 + areaCode; result = result * 31 + prefix; result = result * 31 + lineNumber; hashCode=result; } return hashCode; }
最後,若是你們想深刻學習java的話,建議你們看一看effective java,相信會收穫頗豐的。
Email:sxh13208803520@gmail.com