重寫hashcode

正確重寫hashCode的辦法

[1]. hashCode重寫成相同的值缺點

將全部對象的hashCode都返回同樣的值是不科學的。好比a1和a3這兩個根本不一樣的對象,就沒有必要去比較equals,增長無謂的計算量因此應該對象自己的內容 (屬性)來重寫hashCode。

一旦兩個對象內部不同,就直接斷定出hashCode不同不用再調用equals進行比較

[2]. 正確書寫hashCode的辦法:

【原則】按照equals( )比較兩個對象是否一致條件用到的屬性重寫hashCode()

{1}. 經常使用的辦法就是利用涉及到的的屬性進行線性組合

{2}. 線性組合過程當中涉及到的組合係數自定義便可。

注意,拼接以後的數值不能超過整形的表達範圍。

{3}. 公式:屬性1int形式+ C1*屬性2int形式+  C2*屬性3int形式+ …

【技巧】屬性是引用類型的時候,若是已經重寫過hashCode(),那麼這個引用屬性的int形式就是直接調用屬性已有的hashCode值。

最典型的就是這個屬性是字符串類型的,String類型已經重寫了hashCode()方法,因此直接拿來使用便可。

class Person{
    private String name;
    private int age;
   
    public static void sop(Object o){
        System.out.println(o);
    }
 
    public Person(String name, int age){
        this.name =name;
        this.age =age;
    }
 
    public void setName(String name){
        this.name =name;
    }
   
    public String getName(){
        return this.name;
    }
 
    public void setAge(int age){
        this.age =age;
    }
 
    public int getAge(){
        return this.age;
    }
 
    public String toString(){
        return this.name+"::"+this.age;
    }
 
    //equals已經重寫
public boolean equals(Object obj){
if(!(obj instanceof Person)){
            return false;
        }
   
        Person p =(Person)obj;
 
        //用來查看equals方法是否被調用
        sop(this.name +".......equals......."+ p.name);
        //認爲名字相同而且年齡同樣大的兩個對象是一個
return this.name.equals(p.name) && this.age == p.age;
}
}

(2). 將hashCode()重寫成相同的值-----解決HashSet中重複添加java

[1]. 問題:內容相同可是地址不一樣自定義對象如何避免重複的內容添加到HashSet中?this

【解決辦法】必須重寫hashCodeequals兩個方法spa

{1}. 此時根據底層哈希表的存儲方式:哈希表會將具備相同哈希值的元素依次順延。code

{2}. hashCode值相同,HashSet在存儲對象的時候,equals方法就會起做用orm

{3}. 示例代碼:爲Person類重寫以下的hashCode代碼對象

public int hashCode(){  內存

    System.out.println(this.name +"...hashCode");  字符串

    return 60;  get

}  hash

這樣,每個Person對象都具備相同的哈希值。

打印結果:

HashSet添加過程分析】

【1】a1率先存入HashSet中

添加的時候,調用一次a1的hashCode方法,打印一次a1...hashCode。因爲開始HashSet中沒有內容,因此沒有調用a1的equals方法。

內存圖以下:


 

【2】當a2要存入HashSet的時候,HashSet首先調用a2的hashCode方法,此時打印出a2...hashCode。發現a2的hashCode也是0x3c和a1的地址值都是同樣的,此時要和a1進行內容比較,打印出a2.......equals.......a1。可是發現name和age都不同,因此equals返回false。此時HashSet就將這個a2存到集合中來。

內存圖以下:


 

【3】當a3要存入HashSet的時候,HashSet首先調用a3的hashCode方法,查看有沒有地址相同的元素,此時打印出a3...hashCode。此時集合中已經存在兩個元素a1和a2,發現a3的hashCode也是0x3c和a一、a2的地址值都是同樣的,此時要一一和這些對象的內容進行比較。

       當a3和a2的進行比較時,a3的equals方法被調用,打印出a3.......equals.......a2。 比較發現a3和a2是地址相同可是內容不一樣的元素。

    a3再和a1進行比較,a3的equals方法再次被調用,打印出a3.......equals.......a1。

比較發現a3和a1仍然是地址相同可是內容不一樣的元素。

a3就被認爲是集合中之前並不存在的元素,因此仍然被添加進來。

內存圖以下:


 

【4】當運行到第二個a2要添加進來的時候,先調用hashCode,因此立刻打印a2...hashCode。

可是發現,和a2 hashCode相同的元素有a一、a2和a3。這個a2要和集合中的a一、a2和a3都作內容上是否相同的比較。

    a2先比較集合中的a3,調用a2的equals方法,打印出a2.......equals.......a3。

位置相同,可是內容不一樣。

    a2再比較集合中的a2,調用a2的equals方法,打印出a2.......equals.......a2。

可是發現二者內容、地址均相同,是重複的元素不能加到集合中來,因此沒有必要再把這個a2和集合中的a1進行比較。因此沒有打印a2.......equals.......a1


 

(3). 正確重寫hashCode的辦法

[1]. hashCode重寫成相同的值缺點

將全部對象的hashCode都返回同樣的值是不科學的。好比a1和a3這兩個根本不一樣的對象,就沒有必要去比較equals,增長無謂的計算量因此應該對象自己的內容 (屬性)來重寫hashCode。

一旦兩個對象內部不同,就直接斷定出hashCode不同不用再調用equals進行比較

[2]. 正確書寫hashCode的辦法:

【原則】按照equals( )比較兩個對象是否一致條件用到的屬性重寫hashCode()

{1}. 經常使用的辦法就是利用涉及到的的屬性進行線性組合

{2}. 線性組合過程當中涉及到的組合係數自定義便可。

注意,拼接以後的數值不能超過整形的表達範圍。

{3}. 公式:屬性1int形式+ C1*屬性2int形式+  C2*屬性3int形式+ …

【技巧】屬性是引用類型的時候,若是已經重寫過hashCode(),那麼這個引用屬性的int形式就是直接調用屬性已有的hashCode值。

最典型的就是這個屬性是字符串類型的,String類型已經重寫了hashCode()方法,因此直接拿來使用便可。

e.g. 分析案例

這個例子中,重寫的equals方法中是經過name和age來斷定兩個對象是否一致的。因此,就經過Person的這兩個屬性name和age的線性組合來獲取這個Person的hashCode值。注意到name是String類型的,因此,能夠調用name的hashCode()來直接獲取name對應的int值。

這裏重寫的hashCode方法是:

public int hashCode(){

    sop(this.name +"......hashCode");

    return this.name.hashCode() + 29*age;

}

打印結果:

相關文章
相關標籤/搜索