Java中==、equals、hashcode的區(qū)別?為什么重寫hashcode還要重寫equals?

1.Java中==、equals、hashCode的區(qū)別?

1.1基本數(shù)據(jù)類型使用==與equals


  • java基本數(shù)據(jù)類型包括:byte、short、int、long、float、double、boolean、char
  • 基本數(shù)據(jù)類型使用"=="比較內(nèi)容是否相同,不能使用equals
int d = 2;
int e = 3;
int f = 3;
System.out.println(d == e);//2與3比較
System.out.println(e==f);//3與3比較
//System.out.println(d.equals(f));基本數(shù)據(jù)類型中沒有equals方法
false
true

1.2引用數(shù)據(jù)類型==與equals


  • 引用數(shù)據(jù)類型使用"=="比較棧內(nèi)存地址是否相同
String g = new String("aw1");
String h = new String("aw");
String i = new String("aw");
System.out.println(g==h);//對象g的地址與對象h的地址比較
System.out.println(h==i);//對象h的地址與對象i的地址比較
false
false
  • 引用數(shù)據(jù)類型使用equals先比較對象類型是否相同,再比較堆中對象的內(nèi)容是否相同。
System.out.println(h.equals(i));//對象h的內(nèi)容aw與對象i的內(nèi)容aw比較
System.out.println(h.equals(g));///對象h的內(nèi)容aw與對象g的內(nèi)容aw1比較
true
false
  • 小坑:
  • 包裝類型使用"=="與上述說的有些不一樣,從源碼可看出,包裝類型的值如果在范圍內(nèi),會進行緩存,后面需要使用該對象,直接可以從緩存中取,不會再new對象。但在范圍之外,會在堆上產(chǎn)生新對象,并不會復(fù)用已有對象。包裝類型使用equals與引用數(shù)據(jù)類型一樣。
public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
Integer ina = 1;
Integer inb = 1;
Integer inc = 1000;
Integer ind = 1000;

System.out.println(ina == inb);//在-128~127范圍內(nèi),b直接從緩存中取,地址一樣
System.out.println(inc == ind);//超過127,會產(chǎn)生新對象d,地址不一樣
System.out.println(ina.equals(inb));//equals之比較類型和對應(yīng)內(nèi)容是否一樣,1與1
System.out.println(inc.equals(ind));//1000與1000
true
false
true
true

1.3hashCode


??Java中的集合(Collection)有兩類,一類是List,再有一類是Set。前者集合內(nèi)的元素是有序的,元素可以重復(fù);后者元素?zé)o序,但元素不可重復(fù)。判斷元素是否重復(fù)使用Object.equals方法,但是每增加一個元素,就需要遍歷整個集合,效率會很低。
??于是,Java采用了哈希表的原理,當(dāng)集合要添加新的元素時,先調(diào)用這個元素的hashCode方法,就能定位到它應(yīng)該放置的哈希表中對應(yīng)位置。 如果這個位置上沒有元素,它就可以直接存儲在這個位置上,不用再進行任何比較了;如果這個位置上已經(jīng)有元素了,就調(diào)用它的equals方法與新元素進行比較,相同的話就不存,不相同就散列其它的地址。這樣一來實際調(diào)用equals方法的次數(shù)就大大降低了。

2.為什么要重寫equals還要重寫hashCode?

  • 在HashMap中,如果要比較key值是否相等,要同時使用equals和hashCode,因為自定義類的hashCode方法繼承于Object類,hashCode碼為默認的內(nèi)存地址,這樣即便有相同含義的兩個對象,比較也是不同的。

  • HashMap中比較key值是先求出key的hashCode碼,比較其值是否相等。若相等,再比較equals(),若為true則認為是相等的,若為false則認為是不相等的。如果只重寫的hashCode()方法,不重寫equals()方法,那么只是對它們內(nèi)存地址的比較,所以要兩個方法一起重寫。

  • 關(guān)于hashCode方法,一致的約定是:
    ??1.重寫了euqals方法的對象必須同時重寫hashCode()方法。
    ??2.如果2個對象通過equals調(diào)用后返回是true,那么這個2個對象的hashCode方法也必須返回同樣的int型散列碼
    ??3.如果2個對象通過equals返回false,他們的hashCode返回的值允許相同,最好是不相同。

  • 以下為Student類,只重寫了hashCode(),沒有重寫equals(),雖然s1與s2內(nèi)容相同且hashCode相同,但是equals()比較的是s1與s2內(nèi)存地址是否一樣,所以返回了false。如上約定3所言。

public class Student {
    public String name;
    public int age;
    public double weight;
    public boolean isMarry;

    public Student(String name, int age, double weight, boolean isMarry){
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.isMarry = isMarry;
    }
    @Override
    public int hashCode(){
            int result =  name != null ? name.hashCode():0;
            result = 31*result + age % 10;
            Long temp = Double.doubleToLongBits(this.weight);
            result = 31*result + (int)(temp ^ (temp >>>32));
            result = 31*result + (isMarry ? 1:0);
            return result;
    }
public static void main(String[] args) {
        Student s1 = new Student("hihi",2,52.5,true);
        Student s2 = new Student("hihi",2,52.5,true);
        Student s3 = new Student("hihisas",4,52.5,false);
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(s1.equals(s2));
        System.out.println(s2.equals(s3));
    }
-6555007
-6555007
-2036969151
false
false
  • 重寫equals()后,如上約定2所言,equals返回的是true,那么兩個對應(yīng)的hashCode值必須相等。
    @Override
    public boolean equals(Object object) {
        Student student = (Student) object;
        if(student == null ){
            return false;
        }else if(this.name==student.name&&this.age==student.age&&this.isMarry==student.isMarry&&this.weight==student.weight){
            return true;
        }
        return false;
    }
-6555007
-6555007
-2036969151
true
false

以上僅為學(xué)習(xí)筆記,如有錯誤,請多指教!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容