首頁 > 軟體

Java開發HashMap key必須實現hashCode equals方法原理

2023-03-21 06:00:37

一、問題引入

平時在開發中,相信你多多少少都使用過HashMap,而當你用自定義物件作為key時,很多人會告訴你:你必須要同時實現自定義物件的hashCode、equals方法,否者可能會出問題,於是你就實現了...

可是為什麼呢?比如這裡有自定義物件Person,構造如下:

public class Person {
    private String name;
    private int age;
    private float height;
}

欲將Person作為HashMap的key,放入雜湊表中儲存資訊。我們來探討一下,為什麼要同時實現hashCode、equals方法吧~

Person p1 = new Person("ciusyan", 21, 1.8f);
Person p2 = new Person("ciusyan", 21, 1.8f);
Map<Person, String> map = new HashMap<>();
map.put(p1, "Ciusyan");
map.put(p2, "Zhiyan");

首先要明確:

  • hashCode方法用於計算出物件的雜湊值
  • equlas方法用於比較兩個物件是否相等

二、hashCode、equals方法都未實現

倘若你瞭解雜湊表的基本構造,可以畫出一個草圖:

我們並沒有實現hashCode、equals方法,為什麼還能放入雜湊表中呢?

  • 因為JDK會有預設實現

在預設的實現中:

  • 利用hashCode方法計算出的雜湊值是不同的
  • 利用equals方法比較,p1和p2不是一個物件
  • 所以放入雜湊表中的大致結構如上圖所示:
    • 可能會被放入兩個桶(不同雜湊值計算出的索引不一樣)
    • 也可能會被放入一個桶(不同雜湊值也可能會計算出相同的索引),又因為是不同物件,所以會被串起來

三、只實現hashCode方法

如果我們實現了hashCode方法,會有什麼不同呢?

    @Override
	public int hashCode() {
        int hash = Integer.hashCode(age);
        hash = hash * 31 + Float.hashCode(height);
        hash = hash * 31 + (name == null ? 0 : name.hashCode());
        return hash;
    }

如上實現,既滿足了儘量用的所有資訊,也使計算的值儘量唯一了

如果是現在,我們再來畫一幅草圖:

現在只實現了hashCode方法:

  • 利用hashCode方法計算出的雜湊值是相同的
  • equals方法是預設實現,p1和p2不是一個物件
  • 所以放入雜湊表中的大致結構如上圖所示:
    • 只會被放入一個桶(相同的雜湊值計算出的索引相同),又因為是不同物件,所以會被串起來

四、只實現equals方法

如果我們實現了equals方法,會有什麼不同呢?

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || o.getClass() != getClass()) return false;
        Person p = (Person) o;
        return p.age == age && p.height == height && (Objects.equals(name, p.name));
    }

如上實現,如果兩個物件的age、name、height都相等,那麼可以認為是同一個物件

如果是現在:

現在只實現了equals方法:

  • hashCode方法是預設實現,計算出的雜湊值是不同的
  • 利用equals方法比較,p1和p2是同一個物件
  • 所以放入雜湊表中的大致結構如上圖所示:
    • 可能會被放入兩個桶(計算出的索引不一樣)
    • 也可能會被放入一個桶(不同雜湊值也可能會計算出相同的索引),又因為是同一物件,所以p2的鍵和值會覆蓋掉p1的

五、hashCode、equals方法都實現

倘若我們用上面的實現方式,將hashCode和equals方法都實現了

來看看最終的結構:

現在hashCode、equals方法都實現了:

  • 利用hashCode方法計算出的雜湊值是相同的
  • 利用equals方法比較,p1和p2是同一個物件

所以放入雜湊表中的大致結構如上圖所示:

  • 只會被放入一個桶中(相同的雜湊值計算出的索引相同),又因為是同一物件,所以p2的鍵和值會覆蓋掉p1

六、總結

如果你想要用自定義物件作為HashMap的key,為什麼hashCode、equals方法都要實現?

相信你看完了四種情況,應該能說出個balabala...

那我們一起來balabala一下吧~

  • 先利用hashCode方法計算出雜湊值:
    • 如果雜湊值相同,在雜湊表中計算出的索引肯定相同,會被放入一個桶中。這時候用equals方法檢視是否是相同的物件。
      • 如果是,用新的鍵和值覆蓋掉舊的;
      • 如果不是就用鏈地址法將物件串起來
    • 如果雜湊值不同,在雜湊表中計算的索引也可能相同,也就是可能會被放入一個桶,也可能會被放入兩個桶。
      • 如果被放入一個桶中,同上一樣,檢查equlas方法;
      • 如果放入兩個桶中,則不需要檢視是否equals

一般的開發需求會是第四種,想要用p1和p2作為key儲存資料,會認為它們是同一個物件,它們是同一個key,也就只會儲存一份資料。所以如果不同時實現hashCode、equals方法,會有圖中的種種問題。

以上就是Java開發HashMap key必須實現hashCode equals方法原理的詳細內容,更多關於Java開發HashMap key的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com