How and when override equals() and hashCode()

1. Giới thiệu Chào các bạn hôm nay chúng ta sẽ tìm hiểu một chủ đề không mới lắm, nhưng vẫn luôn là quan trọng cho những ai vẫn còn đang mơ hồ về hai method hashcode() và equals() trong java. Đồng thời tìm hiểu và mục đính sử dụng của hai hàm đó trong Hash collections. Như chúng ta biết thì tất cả các object trong java đều có hỗ trợ hai hàm này. Đầu tiên chúng ta tìm hiểu về hàm hashcode() trong java.

2. Hashcode Mặc định hàm hashCode() được gennerate ra một số integer là unique khi object được khởi tạo trong bộ nhớ heap. Giá trị này là random cho mỗi object nếu phương thức hashCode() không được override. vd:

Thực tế hashCode() được sử dụng khi chúng ta insert object vào Hash Collections, vậy quá trình gọi hàm hashcode() như nào? Trong số chúng ta chắc hẳn không phải ai cũng biết rõ khi nào thì gọi hàm hashcode() và equals(). 😄 mình sẽ giải thích ngay sau đây: Khi add một object vào hashtable, phương thức hashCode() sẽ được gọi và trả về hash code của object, giá trị này được sử dụng để xác định vị trí của object được lưu trữ trong hashtable. Tương tự Khi chúng ta get object từ hashtable, giá trị hash code này được sử dụng để tìm nơi lưu trữ của object trong hashtable. Nếu trong trường hợp hàm hashcode() trả về giá trị trùng với một object được add vào trước đó thì lúc này hàm equals() sẽ được gọi để kiểm tra. Đó là quy trình mà 2 hàm hashcode() và equals() được gọi khi HashCollections add object vào.

3. Equals Mặc định phương thức equals() trả về kết quả phép so sánh ==. Hay nói cách khác để kiểm tra 2 tham chiếu references tới 2 đối tượng cùng kiểu class trong head, nếu không override method equals trong class thì hai object đó không được xem là bằng nhau tại vì references tới 2 object khác nhau sẽ luôn chưa dạng bit khác nhau. Thông thường equals() được override để so sánh object.

Nếu a.equals(b) thì đồng nghĩa với a.hashcode() == b.hashcode().

Nhưng ngược lại:

a.hashcode() == b.hashcode() thì chưa khẳng định được a.quals(b).

vd: trước khi override equals() và hashcode()

class A {
	private String name;
	private int agee;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAgee() {
		return agee;
	}

	public void setAgee(int agee) {
		this.agee = agee;
	}

}

public class MyApplication {
	public static void main(String[] args) {
		A a1 = new A();
		a1.setName("a");
		A a2 = new A();
		a2.setName("a");

		System.out.println(a1.equals(a2));
		System.out.println(a1.hashCode());
		System.out.println(a2.hashCode());

	}
}

kết quả:

false 366712642 1829164700 vd: sau khi override override equals() và hashcode()

@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + agee;
		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;
		A other = (A) obj;
		if (agee != other.agee)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

kết quả:

true 1058 1058

4. Hash collections check duplicate như thế nào với hashcode() và equals(). Như phân tích ở trên, Hash collection sẽ sử dụng hashCode() để xác định được “vị trí” của object và equals() để xác định chính xác object cần tìm. Ngay từ lúc insert object vào Hash Collection thì hashcode() luôn được gọi trước:

  • Nếu giá trị hashcode() khác so với các object có trong hash collections thì object mới được thêm vào luôn.
  • Nếu giá trị hashcode() trùng so với các object có trong hash collections thì hàm equals() sẽ được gọi để xác thực tính equals của object mới đó. Chính là vì hashcode() bằng nhau không đảm bảo là kết quả equals hay không. vd hinh minh họa:

5. Tài liệu tham khảo Các bạn nên tìm đọc cuốn sách này rất hay: HeadFirstJava2ndEdition