1. 程式人生 > >java覆蓋equals()方法時總要覆蓋hashCode()

java覆蓋equals()方法時總要覆蓋hashCode()

我們再用JAVA建立自己的類的時候,一種比較常見的覆蓋就是覆蓋Object中的equals()方法和hashCode()方法。如果不這樣做的話,就很可能違反Object.hashCode()的通用約定,從而在利用自己建的類構建需要Hash化的集合的正常工作。其中有一條約定很重要:

如果兩個物件利用equals方法比較是相等的,那麼這兩個物件必須能返回同樣的hashCode。

這一點很好理解,就比如拿Set來說,Set的特點就是元素是無須的且不可重複。那麼這裡面所謂的重複的定義,就是需要程式設計師通過equals去定義的,既然你覆蓋了equals()方法,那麼也就是你已經定義了重複的概念。那麼如果equals()返回了True就意味著hashCode()必須返回一樣的雜湊碼。

舉個栗子,我這裡新建了三個類:

1.User:沒有覆蓋equals也沒有覆蓋hashCode

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;
	}
	
}
2.EqualUser:只覆蓋equals方法
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;
	}

}
3.HashUser:覆蓋了equals和hashCode方法
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