關於為什麼要重寫hashCode()方法和equals()方法及如何重寫
我想寫的問題有三個:
1、首先我們為什麼需要重寫hashCode()方法和equals()方法
2、在什麼情況下需要重寫hashCode()方法和equals()方法
3、如何重寫這兩個方法
*********************************************************************
第一個問題:為什麼需要重寫hashCode()方法和equals()方法
Java中的超類Object類中定義的equals()方法是用來比較兩個引用所指向的物件的記憶體地址是否一致
Object類中equals()方法的原始碼
public
return (this == obj);
}
********************************************************************
Object類中的hashCode()方法,用native關鍵字修飾,說明這個方法是個原生函式,也就說這個方法的實現不是用java語言實現的,是使用c/c++實現的,並且被編譯成了DLL,由java去呼叫,jdk原始碼中不包含。對於不同的平臺它們是不同的,java在不同的作業系統中呼叫不同的native方法實現對作業系統的訪問,因為java語言不能直接訪問作業系統底層,因為它沒有指標。
這種方法呼叫的過程:
1、在java中申明native方法,然後編譯
2、用javah產生一個 .h 檔案
3、寫一個 .cpp檔案實現native匯出方法,其中需要包含第二步產生的.h檔案(其中又包含了jdk帶的jni.h檔案);
4、將.cpp檔案編譯成動態連結庫檔案
5、在java中用System.loadLibrary()檔案載入第四步產生的動態連結庫檔案,然後這個navite方法就可被訪問了
Java的API文件對hashCode()方法做了詳細的說明,這也是我們重寫hashCode()方法時的原則【Object類】
重點要注意的是:
a. 在java應用程式執行時,無論何時多次呼叫同一個物件時的hsahCode()方法,這個物件的hashCode()方法的返回值必須是相同的一個int值
b. 如果兩個物件equals()返回值為true,則他們的hashCode()也必須返回相同的int值
c. 如果兩個物件equals()返回值為false,則他們的hashCode()返回值也必須不同
public native int hashCode();
現在到了說正題了,為什麼要重寫
我們在定義類時,我們經常會希望兩個不同物件的某些屬性值相同時就認為他們相同,所以我們要重寫equals()方法,按照原則,我們重寫了equals()方法,也要重寫hashCode()方法,要保證上面所述的b,c原則;所以java中的很多類都重寫了這兩個方法,例如String類,包裝類
4、第二個問題:在什麼情況下需要重寫hashCode()方法和equals()方法
當我們自定義的一個類,想要把它的例項儲存在集合中時,我們就需要重寫這兩個方法;集合(Collection)有兩個類,一個是List,一個是Set
List:集合中的元素是有序的,可以重複的
Set:無序,不可重複的
以HashSet來說明:
HashSet存放元素時,根據元素的hashCode值快速找到要儲存的位置,如果這個位置有元素,兩個物件通過equals()比較,如果返回值為true,則不放入;如果返回值為false,則這個時候會以連結串列的形式在同一個位置上存放兩個元素,這會使得HashSet的效能降低,因為不能快速定位了。還有一種情況就是兩個物件的hashCode()返回值不同,但是equals()返回true,這個時候HashSet會把這兩個物件都存進去,這就和Set集合不重複的規則相悖了;所以,我們重寫了equals()方法時,要按照b,c規則重寫hashCode()方法!
5、第三個問題:如何重寫這兩個方法
我寫了一個例子,大家可以看一下
*******************************************************************************
package cn.hashCode.jing;
/**
*定義一個Ponint測試類,用來測試Set集合儲存元素的方式中
*hashCode()方法和equals()方法對Set集合儲存元素影響
*
*/
public final class Point {
private int x;
private int y;
public Point(){
super();
}
public Point(int x,int y){
this.x=x;
this.y=y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(obj!=null && obj.getClass()==Point.class){
Pointpo=(Point)obj;
if(this.x==po.x && this.y==po.y){
return true;
}
}
return false;
}
@Override
public int hashCode(){
return 7*x+31*y;
}
/*以下是自動生成的
@Override
publicboolean equals(Object obj) {
if(this == obj)
returntrue;
if(obj == null)
returnfalse;
if(getClass() != obj.getClass())
returnfalse;
Pointother = (Point) obj;
if(x != other.x)
returnfalse;
if(y != other.y)
returnfalse;
returntrue;
}
@Override
publicint hashCode() {
finalint prime = 31;
intresult = 1;
result= prime * result + x;
result= prime * result + y;
returnresult;
}*/
public String toString(){
return x+","+y+" ";
}
}
package cn.hashCode.jing;
import java.util.HashSet;
public class TestHashSet {
public static void main(String[] args) {
HashSet<Point>hs=new HashSet<Point>();
Pointp1=new Point(3,4);
Pointp2=new Point(6,4);
Pointp3=new Point(10,7);
Pointp4=new Point(8,9);
Pointp5=new Point(3,4);
hs.add(p1);
hs.add(p2);
hs.add(p3);
hs.add(p4);
hs.add(p5);
System.out.println(p1.equals(p5));
System.out.println(p1.hashCode());
System.out.println(p5.hashCode());
System.out.println(hs);
}
}
結果:true
145
145
[3,4 , 6,4 , 10,7 ,8,9 ]