天天看點

Java中的 equals() 和 hashCode() 契約

java.lang.Object類中有兩個非常重要的方法:

public boolean equals(Object obj)

public int hashCode()

了解這兩個方法非常的重要,尤其是将使用者自定義的對象添加到Map中的時候。有時候就算是久經沙場的老程式員也弄不清楚該如何正确使用它們。這篇文章中,我将用一個例子讓大家看看大家經常會犯的錯誤,然後解釋equals()和hashCode()的正确的使用方法。

Java中的 equals() 和 hashCode() 契約

1. 常見錯誤

常見的錯誤如下:

import java.util.HashMap;

public class Apple {

    private String color;

    public Apple(String color) {

        this.color = color;

    }

    public boolean equals(Object obj) {

        if (!(obj instanceof Apple))

            return false;   

        if (obj == this)

            return true;

        return this.color == ((Apple) obj).color;

    public static void main(String[] args) {

        Apple a1 = new Apple("green");

        Apple a2 = new Apple("red");

        //hashMap stores apple type and its quantity

        HashMap m = new HashMap();

        m.put(a1, 10);

        m.put(a2, 20);

        System.out.println(m.get(new Apple("green")));

}

這個例子中,一個“綠蘋果”的對象成功添加到hashMap中了,但是當我們要取出這個“綠蘋果”的時候,卻得不到這個對象,程式傳回null。我們使用調試器卻發現在hashMap中已經存儲了這個對象。

Java中的 equals() 和 hashCode() 契約

2. hashCode()引起的問題

這個問題是因為”hashCode()”方法沒有被重寫。Java中equals()和hashCode()有一個契約:

  1. 如果兩個對象相等的話,它們的hash code必須相等;
  2. 但如果兩個對象的hash code相等的話,這兩個對象不一定相等。

Map的結構能夠快速找到一個對象,而不是進行較慢的線性查找。使用hash過的鍵來定位對象分兩步。Map可以看作是數組的數組。第一個數組的索引就是對鍵采用hashCode()計算出來的值,再在這個位置上查找第二個數組,使用鍵的equals()方法來進行線性查找,直到找到要找的對象。

Object類中的hashCode()對于不同的對象傳回不同的整數,是以上面的例子中,不同的對象(即使相同的類型)也傳回不同的hash值。

Hash碼就像是一個存儲空間的序列,不同的東西放在不同的存儲空間中。将不同的東西整理放在不同的空間中(而不是堆積在一個空間中)更高效。是以能夠均勻的分散hash碼是再好不過了。

上面錯誤的解決方法就是在類中增加hashCode方法。這裡我僅僅使用顔色的長度來計算hash碼。

public int hashCode(){

    return this.color.length();