正確重寫hashCode的辦法


正確重寫hashCode的辦法

http://blog.sina.com.cn/s/blog_700aa8830101jtlf.html

轉自:http://blog.csdn.net/benjaminzhang666/article/details/9468605

 

 

——————————————————————————————————————————

正確重寫hashCode的辦法

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

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

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

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

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

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

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

注意,拼接之后的數值不能超過整形的表達范圍。

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

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

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

——————————————————————————————————————————

 

 

(1). 主要代碼

 

[java]   view plain copy
 
  1. class Person{  
  2.     private String name;  
  3.     private int age;  
  4.      
  5.     public static void sop(Object o){  
  6.         System.out.println(o);  
  7.     }  
  8.    
  9.     public Person(String name, int age){  
  10.         this.name =name;  
  11.         this.age =age;  
  12.     }  
  13.    
  14.     public void setName(String name){  
  15.         this.name =name;  
  16.     }  
  17.      
  18.     public String getName(){  
  19.         return this.name;  
  20.     }  
  21.    
  22.     public void setAge(int age){  
  23.         this.age =age;  
  24.     }  
  25.    
  26.     public int getAge(){  
  27.         return this.age;  
  28.     }  
  29.    
  30.     public String toString(){  
  31.         return this.name+"::"+this.age;  
  32.     }  
  33.    
  34.     //equals已經重寫  
  35. public boolean equals(Object obj){  
  36. if(!(obj instanceof Person)){  
  37.             return false;  
  38.         }  
  39.      
  40.         Person p =(Person)obj;  
  41.    
  42.         //用來查看equals方法是否被調用  
  43.         sop(this.name +".......equals......."+ p.name);  
  44.         //認為名字相同並且年齡一樣大的兩個對象是一個  
  45. return this.name.equals(p.name) && this.age == p.age;  
  46. }  
  47. }  

 

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

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

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

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

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

{3}. 示例代碼:為Person類重寫如下的hashCode代碼

 

[java]   view plain copy
 
  1. public int hashCode(){  
  2.     System.out.println(this.name +"...hashCode");  
  3.     return 60;  
  4. }  

 

這樣,每一個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和a1、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相同的元素有a1、a2和a3。這個a2要和集合中的a1、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}. 公式:屬性1的int形式+ C1*屬性2的int形式+  C2*屬性3的int形式+ …

【技巧】當屬性是引用類型的時候,如果已經重寫過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;

}

打印結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM