不一樣時重寫equals和hashCode又怎樣

閱讀原文:不一樣時重寫equals和hashCode又怎樣!java

可能一問到equals和hashCode相關的問題,就會有人講他們的自反性,對稱性,一致性,傳遞性等幾條約定了,
此時我不得不佩服,這麼多約定居然都能記得,但我不知道你是否是真的理解呢。算法

我不一樣時重寫又能如何呢?

我只能說只要你不碰到這幾個主,你也沒什麼事的!微信

  • 爲何不能遇到它們幾個呢?

    由於它們幾個會用到hashCode方法。ide

  • 他們用hashCode方法來幹嗎?

    hashCode方法是根據對象的地址生成的一個int整數,默認它和地址一一對應的,若是不重寫,那麼只有對象地址同樣的狀況下,哈希值才相等。this

    equals默認用來比較地址是否相同,但當集合中元素增多時,再使用equals判斷,效率是比較低的;而哈希值是能夠快速定位到指定的元素的,
    因此默認Java就使用哈希值來比較定位,所以有了Object.hashCode的約定。spa

    Set怎麼實現存儲不重複的元素的?HashMap怎麼判斷相同的key的?有興趣可去深刻了解一下。code

例子

小王在「堆」中有兩套房產,這兩套房產位於不一樣的地址。如今我想要判斷這兩套房子是不是同一個主人?對象

因而我去問Object,而Object告訴我這兩套房產不是一我的的!token

我:爲何呢?rem

Object: equals告訴我兩套房子離了十萬八千里,在不一樣的地方(地址),固然不是同一我的了。

我:這邏輯……(不符合咱們常規的認知啊)

既然這樣,那我只能重寫equals了!

//注意:這是僞代碼,省略了不少
//重寫equals,認爲身份證相同就是同一我的
@Override
public boolean equals(Object obj) {
   return this.idCard == obj.idCard;
}

哈哈,好啦,如今equals終於知道這兩個房子是同一人的啦!

然而在房產管理局(HashMap)我獲得一個消息:小王只要一套房產!

WTF!我白乾了!

房產管理局(HashMap): 不信你看!

HashMap<Object, Integer> roomManager = new HashMap<>();

    public void count(){
        User u1 = new User("小王", "34128");
        countRoom(u1);
        User u2 = new User("小王", "34128");
        countRoom(u2);
    }
    public void countRoom(User user){
        boolean exist = roomManager.containsKey(user);
        if (exist) {
            Integer num = roomManager.get(user);
            roomManager.put(user, num++);
        }else {
            roomManager.put(user, 1);
        }
    }

遇到你真是倒黴了,原來房產管理局(HashMap)使用了hashCode來計算的!想要正確的統計小王的房產只能重寫hashCode方法了。

@Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (idCard != null ? idCard.hashCode() : 0);
        return result;
    }

此時,他們統計終於對了!!!

總結

除非你能保證你重寫equals的類不被Set,Map使用,不然你就必須同時重寫equals和hashCode。

你能保證嗎?若是不想同時重寫,你能夠這樣:

/**
 * 1.此類應用於Set,Map時,須要使用者重寫hashCode,違規者後果自負
 * 2.本類不能做爲第三方類庫供其餘項目使用 
 * @author flyhero
 * @date 2019-04-03 6:14 PM
 */
public class User {}

信不信這樣寫,老大看到後,就say goodbye了!

如何重寫equals與hashCode

我就不寫出常說的那些約定性質了,寫了也記不住。說說如何避免違反這些約定:

重寫equals

  1. 經過==判斷是不是同一個引用
  2. 經過instanceof判斷是不是相同類型
  3. 把參數轉爲正確的類型
  4. 對比雙方各個屬性值是否相同

如:

@Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof User)) {
            return false;
        }
        User user = (User) obj;
        return this.name.equals(user.name)
                && this.idCard.equals(user.idCard);
    }

重寫hashCode

hashCode方法應該爲「不相等的對象產生不相等的哈希值」

通常計算是根據你equals中用來比較的屬性的hashCode組合計算的,不過目前JDK和一些類庫已經給我提供了很好的重寫方式,咱們可沒必要去深究其中算法。

  • 方式一

    @Override
    public int hashCode() {
        return Objects.hash(name, idCard);
    }

    使用了JDK自帶Objects提供的靜態方法。

  • 方式二

    @EqualsAndHashCode
    public class User {}

    使用了lombok類庫,直接在類上註解便可。

更多精彩技術文章盡在微信公衆號:碼上實戰

相關文章
相關標籤/搜索