ทุก Java object มีเมธอดสำคัญ 2 ตัวคือ equals() และ hashCode() และเมธอดเหล่านี้ถูกออกแบบให้ override ตาม general contract เฉพาะของมัน คลาส Object เป็น parent class ของทุกคลาส การ implement เริ่มต้นของเมธอดทั้งสองนี้มีอยู่ในแต่ละคลาสแล้ว อย่างไรก็ตาม เราสามารถ override เมธอดเหล่านี้ตามความต้องการได้
hashCode() Method
public int hashCode()
เมธอดนี้คืนค่า integer ซึ่งเรียกว่า hash code value ของออบเจ็กต์ ทุก Object ขณะสร้างจะถูกกำหนดค่า 32-bit signed int ที่ไม่ซ้ำกัน ค่านี้คือ hash code value ของออบเจ็กต์นั้น
General contract ของ hashCode() method
- เมธอด hashCode() ควรคืนค่า integer เดียวกันสำหรับออบเจ็กต์เดียวกัน ทุกครั้งที่เรียก เมธอดนี้ ยกเว้นค่าที่เก็บในออบเจ็กต์ถูกแก้ไข
- ถ้าออบเจ็กต์สองตัวเท่ากัน (ตาม equals() method) แล้ว hashCode() ควรคืนค่า integer เดียวกันสำหรับทั้งสองออบเจ็กต์
- แต่ ไม่จำเป็น ที่ hashCode() จะคืนค่าที่แตกต่างกันสำหรับออบเจ็กต์ที่ไม่เท่ากัน (ตาม equals() method)
equals() Method
public boolean equals(Object obj)
เมธอด equals() ของ Object class ตรวจสอบความเท่ากันของออบเจ็กต์ และคืนค่า true หรือ false ตามลำดับ การ implement เริ่มต้นจาก Object class ตรวจสอบความเท่ากันจาก reference ว่าอ้างอิงออบเจ็กต์เดียวกันหรือไม่ ไม่ได้ตรวจสอบค่าหรือ state ของออบเจ็กต์ แต่เราสามารถ override เมธอดนี้เพื่อให้ implementation เปรียบเทียบ state หรือ value ของออบเจ็กต์ได้
General contract ของ equals() method
สำหรับ reference variables a, b, c ที่ไม่เป็น null
- a.equals(a) ควรคืน true เสมอ
- a.equals(b) ควรคืน true ก็ต่อเมื่อ b.equals(a) คืน true
- ถ้า a.equals(b) คืน true และ b.equals(c) คืน true แล้ว a.equals(c) ควรคืน true
- การเรียก a.equals(b) หลายครั้ง ควรคืน true ตลอด หรือ false ตลอด หากค่าของออบเจ็กต์ไม่ได้ถูกแก้ไขสำหรับออบเจ็กต์ใดออบเจ็กต์หนึ่ง
- a.equals(null) ควรคืน false
ดังนั้น จึงจำเป็นต้อง override เมธอด hashCode() ของ Object class หากเรา override เมธอด equals()
ตัวอย่าง
public class MainClass {
public static void main(String[] args) {
MainClass mainClass = new MainClass();
TestClass obj1 = new TestClass(1);
TestClass obj2 = new TestClass(1);
mainClass.test1(obj1, obj2);
TestClass obj3 = new TestClass(1);
TestClass obj4 = new TestClass(2);
mainClass.test2(obj3, obj4);
}
public void test1(TestClass obj1, TestClass obj2) {
if (obj1.equals(obj2)) {
System.out.println("Object One and Object Two are equal");
} else {
System.out.println("Object One and Object Two are not equal");
}
}
public void test2(TestClass obj3, TestClass obj4) {
if (obj3.equals(obj4)) {
System.out.println("Object Three and Object Four are equal");
} else {
System.out.println("Object Three and Object Four are not equal");
}
}
}
class TestClass {
private int val;
TestClass(int val) {
this.val = val;
}
public int getValue() {
return val;
}
@Override
public boolean equals(Object o) {
// null check
if (o == null) {
return false;
}
// this instance check
if (this == o) {
return true;
}
// instanceof Check and actual value check
if ((o instanceof TestClass) && (((TestClass) o).getValue() == this.val)) {
return true;
}
else {
return false;
}
}
@Override
public int hashCode() {
int result = 0;
result = (int) (val / 11);
return result;
}
}
ผลลัพธ์
Object One and Object Two are equal Object Three and Object Four are not equal