java覆蓋equals()方法時總要覆蓋hashCode()
阿新 • • 發佈:2019-01-25
我們再用JAVA建立自己的類的時候,一種比較常見的覆蓋就是覆蓋Object中的equals()方法和hashCode()方法。如果不這樣做的話,就很可能違反Object.hashCode()的通用約定,從而在利用自己建的類構建需要Hash化的集合的正常工作。其中有一條約定很重要:
如果兩個物件利用equals方法比較是相等的,那麼這兩個物件必須能返回同樣的hashCode。
這一點很好理解,就比如拿Set來說,Set的特點就是元素是無須的且不可重複。那麼這裡面所謂的重複的定義,就是需要程式設計師通過equals去定義的,既然你覆蓋了equals()方法,那麼也就是你已經定義了重複的概念。那麼如果equals()返回了True就意味著hashCode()必須返回一樣的雜湊碼。
舉個栗子,我這裡新建了三個類:
1.User:沒有覆蓋equals也沒有覆蓋hashCode
2.EqualUser:只覆蓋equals方法package com.blog.hash; public class User { private int id; private String name; public User(int id, String name) { // TODO Auto-generated constructor stub this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3.HashUser:覆蓋了equals和hashCode方法package com.blog.hash; public class EqualUser { private int id; private String name; public EqualUser(int id, String name) { // TODO Auto-generated constructor stub this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } 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 == null) return false; if (getClass() != obj.getClass()) return false; EqualUser other = (EqualUser) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
package com.blog.hash;
public class HashUser {
private int id;
private String name;
public HashUser(int id, String name) {
// TODO Auto-generated constructor stub
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
HashUser other = (HashUser) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
除此之外還寫了一個測試類MyTest
package com.blog.hash;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
public class MyTest {
@Test
public void withoutOveride() {
User u1 = new User(1, "mike");
User u2 = new User(1, "mike");
Set<User> set = new HashSet();
set.add(u1);
set.add(u2);
System.out.println(u1.equals(u2));
for (User u : set) {
System.out.println(u.getId() + u.getName());
}
}
@Test
public void withAllOveride() {
HashUser u1 = new HashUser(1, "mike");
HashUser u2 = new HashUser(1, "mike");
Set<HashUser> set = new HashSet();
set.add(u1);
set.add(u2);
System.out.println(u1.equals(u2));
for (HashUser u : set) {
System.out.println(u.getId() + u.getName());
}
}
@Test
public void withEqualOveride() {
EqualUser u1 = new EqualUser(1, "mike");
EqualUser u2 = new EqualUser(1, "mike");
Set<EqualUser> set = new HashSet();
set.add(u1);
set.add(u2);
System.out.println(u1.equals(u2));
for (EqualUser u : set) {
System.out.println(u.getId() + u.getName());
}
}
}
在方法withoutOveride中,新建了兩個User物件,因為User沒有覆蓋equals也沒有覆蓋hashCode,所以呼叫的是Object的方法。因此equals比較的是引用,所以equals()返回false,列印結果為:
false
1mike
1mike
這裡u1和u2明顯是同一個值,只是引用不一樣,所以在實際使用的時候會覆蓋equals方法。
在方法withEqualOveride中,建立兩個EqualUser物件,由於覆蓋了equals方法而沒有覆蓋hashCode,所以呼叫equals時返回true,而hashCode還是Object的方法,列印結果為:
true
1mike
1mike
這樣在set中就存在了重複的值,所以會導致在使用hash話的集合的時候出現問題。
最後,在方法withAllOveride中,由於覆蓋了equals和hashCode方法,因此呼叫equals方法的時候返回的是true,同時set中沒有重複的值,列印結果為:
true
1mike