天天看點

關于equals與hashcode的重寫

我想寫的問題有三個:

1、首先我們為什麼需要重寫hashCode()方法和equals()方法

2、在什麼情況下需要重寫hashCode()方法和equals()方法

3、如何重寫這兩個方法

*********************************************************************

第一個問題:為什麼需要重寫hashCode()方法和equals()方法

    中的超類Object類中定義的equals()方法是用來比較兩個引用所指向的對象的記憶體位址是否一緻

Object類中equals()方法的源碼

public boolean equals(Object obj) {

       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;

    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())

       Pointother = (Point) obj;

       if(x != other.x)

       if(y != other.y)

       returntrue;

    publicint hashCode() {

       finalint prime = 31;

       intresult = 1;

       result= prime * result + x;

       result= prime * result + y;

       returnresult;

    }*/

    public String toString(){

       return x+","+y+" ";

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);

下一篇: 蝸牛上天