[ 轉載 ]hashCode方法的相關用法

想要明白hashCode的做用,你必需要先知道Java中的集合。java

   

總的來講,Java中的集合(Collection)有兩類,一類是List,再有一類是Set。 算法

你知道它們的區別嗎?前者集合內的元素是有序的,元素能夠重複;後者元素無序,但元素不可重複。 數據結構

 

那麼這裏就有一個比較嚴重的問題了:要想保證元素不重複,可兩個元素是否重複應該依據什麼來判斷呢? 
這就是Object.equals方法了。可是,若是每增長一個元素就檢查一次,那麼當元素不少時,後添加到集合中的元素比較的次數就很是多了。 
也就是說,若是集合中如今已經有1000個元素,那麼第1001個元素加入集合時,它就要調用1000次equals方法。這顯然會大大下降效率。    
因而,Java採用了哈希表的原理。哈希(Hash)其實是我的名,因爲他提出一哈希算法的概念,因此就以他的名字命名了。 
哈希算法也稱爲散列算法,是將數據依特定算法直接指定到一個地址上。若是詳細講解哈希算法,那須要更多的文章篇幅,我在這裏就不介紹了。 
初學者能夠這樣理解,hashCode方法實際上返回的就是對象存儲的物理地址(實際可能並非)。   
這樣一來,當集合要添加新的元素時,先調用這個元素的hashCode方法,就一會兒能定位到它應該放置的物理位置上。 
若是這個位置上沒有元素,它就能夠直接存儲在這個位置上,不用再進行任何比較了;若是這個位置上已經有元素了, 
就調用它的equals方法與新元素進行比較,相同的話就不存了,不相同就散列其它的地址。 this

因此這裏存在一個衝突解決的問題。這樣一來實際調用equals方法的次數就大大下降了,幾乎只須要一兩次。spa

   

因此,Java對於eqauls方法和hashCode方法是這樣規定的: .net

一、若是兩個對象相同,那麼它們的hashCode值必定要相同;二、若是兩個對象的hashCode相同,它們並不必定相同     上面說的對象相同指的是用eqauls方法比較。   3d

 

你固然能夠不按要求去作了,但你會發現,相同的對象能夠出如今Set集合中。同時,增長新元素的效率會大大降低。code

 

根據官方文檔的定義,咱們能夠抽出成以對象

下幾個關鍵點:排序

 

 

一、hashCode的存在主要是用於查找的快捷性,如Hashtable,HashMap等,hashCode是用來在散列存儲結構中肯定對象的存儲地址的;

二、若是兩個對象相同,就是適用於equals(Java.lang.Object) 方法,那麼這兩個對象的hashCode必定要相同;

三、若是對象的equals方法被重寫,那麼對象的hashCode也儘可能重寫,而且產生hashCode使用的對象,必定要和equals方法中使用的一致,不然就會違反上面提到的第2點;

四、兩個對象的hashCode相同,並不必定表示兩個對象就相同,也就是不必定適用於equals(java.lang.Object) 方法,只可以說明這兩個對象在散列存儲結構中,如Hashtable,他們「存放在同一個籃子裏」。

 

再概括一下就是hashCode是用於查找使用的,而equals是用於比較兩個對象的是否相等的。

如下這段話是從別人帖子回覆拷貝過來的:

  1.  
    1.hashcode是用來查找的,若是你學過數據結構就應該知道,在查找和排序這一章有
  2.  
    例如內存中有這樣的位置
  3.  
    0 1 2 3 4 5 6 7
  4.  
    而我有個類,這個類有個字段叫ID,我要把這個類存放在以上 8個位置之一,若是不用hashcode而任意存放,那麼當查找時就須要到這八個位置裏挨個去找,或者用二分法一類的算法。
  5.  
    但若是用hashcode那就會使效率提升不少。
  6.  
    咱們這個類中有個字段叫ID,那麼咱們就定義咱們的hashcode爲ID% 8,而後把咱們的類存放在取得得餘數那個位置。好比咱們的ID爲9,9除8的餘數爲1,那麼咱們就把該類存在1這個位置,若是ID是13,求得的餘數是5,那麼咱們就把該類放在5這個位置。這樣,之後在查找該類時就能夠經過ID除 8求餘數直接找到存放的位置了。
  7.  
     
  8.  
    2.可是若是兩個類有相同的hashcode怎麼辦那(咱們假設上面的類的ID不是惟一的),例如9除以8和17除以8的餘數都是1,那麼這是否是合法的,回答是:能夠這樣。那麼如何判斷呢?在這個時候就須要定義 equals了。
  9.  
    也就是說,咱們先經過 hashcode來判斷兩個類是否存放某個桶裏,但這個桶裏可能有不少類,那麼咱們就須要再經過 equals 來在這個桶裏找到咱們要的類。
  10.  
    那麼。重寫了 equals(),爲何還要重寫hashCode()呢?
  11.  
    想一想,你要在一個桶裏找東西,你必須先要找到這個桶啊,你不經過重寫hashcode()來找到桶,光重寫 equals()有什麼用啊

如下這段話是從別人帖子回覆拷貝過來的:

  1.  
    public class HashTest {
  2.  
    private int i;
  3.  
     
  4.  
    public int getI() {
  5.  
    return i;
  6.  
    }
  7.  
     
  8.  
    public void setI(int i) {
  9.  
    this.i = i;
  10.  
    }
  11.  
     
  12.  
    public int hashCode() {
  13.  
    return i % 10;
  14.  
    }
  15.  
     
  16.  
    public final static void main(String[] args) {
  17.  
    HashTest a = new HashTest();
  18.  
    HashTest b = new HashTest();
  19.  
    a.setI( 1);
  20.  
    b.setI( 1);
  21.  
    Set<HashTest> set = new HashSet<HashTest>();
  22.  
    set.add(a);
  23.  
    set.add(b);
  24.  
    System. out.println(a.hashCode() == b.hashCode());
  25.  
    System. out.println(a.equals(b));
  26.  
    System. out.println(set);
  27.  
    }
  28.  
    }

這是輸出結果:

  1.  
    true
  2.  
    false
  3.  
    [com.ubs.sae.test. HashTest@1, com.ubs.sae.test.HashTest@1]

以上這個示例,咱們只是重寫了hashCode方法,從上面的結果能夠看出,雖然兩個對象的hashCode相等,可是實際上兩個對象並非相等;,咱們沒有重寫equals方法,那麼就會調用object默認的equals方法,是比較兩個對象的引用是否是相同,顯示這是兩個不一樣的對象,兩個對象的引用確定是不定的。這裏咱們將生成的對象放到了HashSet中,而HashSet中只可以存放惟一的對象,也就是相同的(適用於equals方法)的對象只會存放一個,可是這裏其實是兩個對象a,b都被放到了HashSet中,這樣HashSet就失去了他自己的意義了。

 

此時咱們把equals方法給加上:

  1.  
    public class HashTest {
  2.  
    private int i;
  3.  
     
  4.  
    public int getI() {
  5.  
    return i;
  6.  
    }
  7.  
     
  8.  
    public void setI(int i) {
  9.  
    this.i = i;
  10.  
    }
  11.  
     
  12.  
    <span style= "color:#3366FF;"><strong>public boolean equals(Object object) {
  13.  
    if (object == null) {
  14.  
    return false;
  15.  
    }
  16.  
    if (object == this) {
  17.  
    return true;
  18.  
    }
  19.  
    if (!(object instanceof HashTest)) {
  20.  
    return false;
  21.  
    }
  22.  
    HashTest other = (HashTest) object;
  23.  
    if (other.getI() == this.getI()) {
  24.  
    return true;
  25.  
    }
  26.  
    return false;
  27.  
    }</strong></span>
  28.  
     
  29.  
    public int hashCode() {
  30.  
    return i % 10;
  31.  
    }
  32.  
     
  33.  
    public final static void main(String[] args) {
  34.  
    HashTest a = new HashTest();
  35.  
    HashTest b = new HashTest();
  36.  
    a.setI( 1);
  37.  
    b.setI( 1);
  38.  
    Set<HashTest> set = new HashSet<HashTest>();
  39.  
    set.add(a);
  40.  
    set.add(b);
  41.  
    System. out.println(a.hashCode() == b.hashCode());
  42.  
    System. out.println(a.equals(b));
  43.  
    System. out.println(set);
  44.  
    }
  45.  
    }

此時獲得的結果就會以下:

  1.  
    true
  2.  
    true
  3.  
    [ com.ubs.sae.test.HashTest@1]

從結果咱們能夠看出,如今兩個對象就徹底相等了,HashSet中也只存放了一份對象。

相關文章
相關標籤/搜索