iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0
自我挑戰組

從0開始學習Java系列 第 14

Set成功範例,覆寫hashCode 和equals方法

  • 分享至 

  • xImage
  •  
package ecpay_practice2;

import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class HashSetPractice2 {
	public static void main(String[] args) {
		// 版本二:正確的示範 (The Correct Version)
		Set<CorrectUser> onlineUsers = new HashSet<>();
		System.out.println("--- 開始新增使用者 ---");

		CorrectUser alice1 = new CorrectUser("Alice");
		CorrectUser alice2 = new CorrectUser("Alice"); // 內容相同的物件
		CorrectUser bob = new CorrectUser("Bob");

		onlineUsers.add(alice1);
		onlineUsers.add(bob);
		onlineUsers.add(alice2);
		
		System.out.println(onlineUsers);
		//結果分析:這次 Set 第二個 "Alice" 物件沒有被加進去。

	}
}

//1. 定義 User 類別 (正確覆寫 equals 和 hashCode)
class CorrectUser {
	private String username;

	public CorrectUser(String username) {
		super();
		this.username = username;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public String toString() {
		return "CorrectUser{" + "Fusername='" + username + '\'' + '}';
	}

	// 2. 覆寫 equals 方法,父類別為Object
	// 我們的邏輯:只要 username 相同,就認為是同一個 User
	@Override
	public boolean equals(Object obj) {
		// 如果是同一個記憶體位址,肯定是同一個物件
		if (this == obj)
			return true;

		// 如果傳入的物件是 null,或是不是同一個類別,肯定不相等
		if (obj == null || getClass() != obj.getClass())
			return false;

		// 將物件轉型為 CorrectUser
		CorrectUser that = (CorrectUser) obj;

		// 使用 Objects.equals 來比較 username,這樣可以安全地處理 username 是 null 的情況
		return Objects.equals(username, that.username);

	}

	// 3. 覆寫 hashCode 方法
	// **重要規則**:如果 equals() 返回 true,那麼 hashCode() 必須返回相同的值。
	// 所以我們也只基於 username 來產生 hash code。
	@Override
	public int hashCode() {
		return Objects.hash(username);
	}
}

一、Gotcha Version失效原因

  1. User 類別未覆寫 equals() 和 hashCode(),所以使用 Object 的預設版本。
  2. Object 的預設 hashCode(): 通常是根據記憶體位址計算的。user1 和 user2 是兩個不同的 new 出來的物件,所以記憶體位址不同,hashCode() 也不同
  3. Object 的預設 equals(): 等同於 ==,比較的是記憶體位址。就算 HashSet 意外地讓它們進行了比較,user1 == user2 的結果也是 false。

二、總結

  1. toString():為了方便除錯和閱讀,應該覆寫它,讓它回傳有意義的物件狀態。
  2. hashCode() & equals():要把自訂物件(如 User)放進 HashSet, HashMap 等基於哈希的集合時,必須同時覆寫這兩個方法。
  3. 兩者之間的契約
    equals() 相等的物件,hashCode() 必須相等。 
  4. 覆寫的邏輯:在 equals() 方法中用來比較的欄位(例如 username),也必須被用來計算 hashCode(),這樣才能保證上述契約的成立。

上一篇
Set介面-錯誤小範例
下一篇
小範例
系列文
從0開始學習Java21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言