Java 基礎:hashCode方法

來源:互聯網
上載者:User

標籤:

Writer:BYSocket(泥沙磚瓦漿木匠)

微博:BYSocket

豆瓣:BYSocket

一、前言

    泥瓦匠最近被項目搞的天昏地暗。發現有些要給自己一些目標,關於技術的目標:

專註很重要。專註Java 基礎 + H5(學習)

    其他動作系統,演算法,資料結構當成課外書博覽。有時候,就是那樣你越是專註方面越多對自己打擊越大學啥啥都不好。今天帶來Java基礎:hashCode方法

 

二、hashCode方法

    hash code(散列碼,也可以叫雜湊碼值)是對象產生的一個整型值。其產生沒有規律的。二者散列碼可以擷取對象中的資訊,轉成那個對象的“相對唯一”的整型值。所有對象都有一個散列碼,hashCode()是根類 Object 的一個方法。散列表的工作原理在Java基礎不展開講,只要知道它是一種快速的“字典”即可。下面引用老外一張圖:

 

三、兩個小例子

    首先泥瓦匠引用一段來自 Object規範 【JavaSE6】:

hashCode的常規協定是:

    • 1、在 Java 應用程式執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的資訊沒有被修改。從某一應用程式的一次執行到同一應用程式的另一次執行,該整數無需保持一致。
  • 2、如果根據 equals(Object) 方法,兩個對象是相等的,那麼對這兩個對象中的每個對象調用 hashCode 方法都必鬚生成相同的整數結果。
    • 3、如果根據equals方法,兩個對象不相等,那麼對這兩個對象中的任一對象上調用 hashCode 方法 要求一定產生不同的整數結果。但是,程式員應該意識到,為不相等的對象產生不同整數結果可以提高雜湊表的效能。
  •     由於hashCode定義在根類Object,所以每個對象都是Object,都具有一個預設的散列值,即是對象的儲存地址。泥瓦匠請大家看一下這個例子:
?
1234567891011121314151617 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 一下,可以在控制台看到:

?
1234 hashCode1: 147696667 1385112968hashCode2: 147696667 870919696s  s1 : truesb sb1: false

   泥瓦匠小結

1、s 與 s1相等,且hashCode一樣。驗證了【hashCode的常規協定】的第二條。原因是字串的散列碼由內容匯出的。(這個第二個例子我們會驗證)

2、StringBuilder 裡面沒有定義hashCode方法,所以匯出的是Object預設的對Object Storage Service的地址。(注意到Object的hashCode方法前面有個native的修飾符,這表示hashCode方法是由非java語言實現的,具體的方法實現在外部,返回記憶體對象的地址。)詳情請看認識&理解關鍵字 native 實戰篇。

 

    泥瓦匠剛剛提到字串散列碼是由內容匯出的。下面看看String的hashCode的實現。

?
12345678910111213141516171819202122232425    /** 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;}

    泥瓦匠小結

1、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》中的結論點:

1、如果對象有相同的散列碼,被映射到同一個散列桶,這樣散列表退化稱為 鏈表 ,這樣效能降低。

2、相等的對象必須具有相等的散列碼

3、為不相等的對象產生不相等的散列碼

4、不要試圖從散列碼計算中排除掉一個對象關鍵區段來提高效能

Writer:BYSocket(泥沙磚瓦漿木匠)

微博:BYSocket

豆瓣:BYSocket

Java 基礎:hashCode方法

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.