一. equals的使用
用來判斷兩個對象是否相等。
- 類如果沒有重寫Object的equals方法,則調用Object的equals方法,比較的是對象在堆中的地址是否相等
- 類如果重寫了equals方法,一般用來比較對象的屬性是否相等
二. 爲什麼要重寫equals?
爲什麼要重寫equals方法?主要看使用場景,如果不需要進行對象比較就不需要重寫。
舉個栗子,用戶要修改用戶名,傳了個User對象過來,此時從DB裏取出舊的User對象,比較兩個是不是相等的(其實是比較用戶名),如果沒有重寫equals方法,用的是Object的equals方法,比較對象的地址,與我們的意願相違背。
例子1
public class Main {
public static void main(String[] args) {
User newUser = new User("dkangel");
User dbUser = new User("dkangel");
System.out.println(newUser.equals(dbUser));
}
}
1. 未重寫equals方法,結果爲false
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. 重寫equals方法,結果爲true
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 重寫equals方法,比較name屬性是否相等
*
* @param obj 待比較對象
* @return boolean
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof User)) {
return false;
}
User user = (User) obj;
return Objects.equals(user.name, this.getName());
}
}
三. 重寫了equals方法一定要重寫hashCode方法嗎?爲什麼?
hashCode方法的作用是獲取哈希碼(也稱散列碼),哈希碼的作用是確定對象在哈希表中的位置。
先看下 hashCode 與 equals 的相關規定
- 如果兩個對象相等,則 hashcode 一定也是相同的
- 兩個對象相等,對兩個對象分別調用 equals 方法都返回 true
- 兩個對象有相同的 hashcode 值,它們也不一定是相等的
- hashCode方法的默認行爲是對堆上的對象產生獨特值。如果沒有重寫 hashCode方法,則該類的兩個對象無論如何都不會相等(即使這兩個對象指向相同的數據)
從約定上看:重寫equals方法必須重寫hashCode方法。
從使用上看:
-
如果類在使用過程中不需要創建類對應的哈希表(就是不會在HashMap/HashSet/HashTable等用到hash的數據數據裏用到該類),那就與hashCode方法沒什麼關係,也就不需要重寫hashCode方法。如上面的例子1,只重寫了equals方法,沒有重寫hashCode方法,並不影響使用。
-
如果類在使用過程中需要創建類對應的哈希表,那就需要重寫hashCode方法,爲什麼?再舉個栗子
例子2
當你把對象加入 HashSet 時,HashSet 會先計算對象的 hashcode 值來判斷對象加入的位置,同時也會與該位置其他已經加入的對象的 hashcode 值作比較,如果沒有相符的 hashcode,HashSet 會假設對象沒有重複出現。但是如果發現有相同 hashcode 值的對象,這時會調用 equals()方法來檢查 hashcode 相等的對象是否真的相同。如果兩者相同,HashSet 就不會讓其加入操作成功。如果不同的話,就會重新散列到其他位置。
public class Main {
public static void main(String[] args) {
User newUser = new User("dkangel");
User dbUser = new User("dkangel");
User otherUser = new User("zhangsan");
HashSet<User> users = new HashSet();
users.add(newUser);
users.add(dbUser);
users.add(otherUser);
System.out.println("users size: " + users.size());
users.forEach(user -> System.out.printf("name: %s, hashCode: %s\n", user.getName(), user.hashCode()));
}
}
1. 未重寫hashCode方法
結果爲3
,兩個name爲“dkangel”的對象由於未重寫hashCode方法,導致set中出現重複值。
2. 重寫hashCode方法
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof User)) {
return false;
}
User user = (User) obj;
return Objects.equals(user.name, this.getName());
}
@Override
public int hashCode() {
return this.name.hashCode();
}
}
結果爲2
,重寫了hashCode方法兩個name爲“dkangel”的對象只添加了一個到set裏。