การเอาชนะวิธีการเท่ากับ () และ hashCode () ใน Java
Equals
และhashCode
เป็นวิธีการพื้นฐานที่ประกาศในคลาสObject
และมีอยู่ในไลบรารี Java มาตรฐาน วิธีการนี้еquals()
ใช้ในการเปรียบเทียบวัตถุและhashCode
สร้างรหัสจำนวนเต็มสำหรับวัตถุ วิธีการเหล่านี้ใช้กันอย่างแพร่หลายในไลบรารีมาตรฐาน Java เมื่อแทรกและดึงอ็อบเจ็กต์ในHashMap
. วิธีการนี้equal
ยังใช้เพื่อให้แน่ใจว่ามีการจัดเก็บเฉพาะอ็อบเจ็กต์ที่ไม่ซ้ำกันใน การใช้งาน HashSet
อื่นๆSet
รวมถึงในกรณีอื่นๆ ที่จำเป็นต้องเปรียบเทียบอ็อบเจ็กต์ การใช้งานเริ่มต้นของวิธีการequals()
ในคลาสjava.lang.Object
จะเปรียบเทียบการอ้างอิงไปยังที่อยู่หน่วยความจำที่ตัวแปรจัดเก็บและส่งกลับtrue
เฉพาะในกรณีที่ที่อยู่ตรงกัน กล่าวคือ ตัวแปรอ้างอิงถึงวัตถุเดียวกัน Java แนะนำให้แทนที่ วิธีการ equals()
และhashCode()
หากคุณคาดว่าการเปรียบเทียบจะดำเนินการตามตรรกะทางธรรมชาติหรือตรรกะทางธุรกิจ คลาสจำนวนมากในไลบรารี Java มาตรฐานจะแทนที่คลาสเหล่านั้น เช่น คลาสString
จะแทนที่equals
เพื่อที่จะส่งคืนtrue
หากเนื้อหาของทั้งสองอ็อบเจ็กต์ที่ถูกเปรียบเทียบเหมือนกัน คลาส wrapper จะแทนที่ Integer
วิธีequal
การดำเนินการเปรียบเทียบเชิงตัวเลข และอื่นๆ เนื่องจากJava HashMap
ยัง อาศัย และ วิธีการ ในการเปรียบเทียบและJava จึงเสนอกฎต่อไปนี้สำหรับการแทนที่วิธีการเหล่านี้: HashTable
equals()
hashCode()
key
values
- การสะท้อนกลับ: วัตถุจะต้องเท่ากับตัวมันเอง
- สมมาตร: หาก
a.equals(b)
ส่งคืนtrue
ก็b.equals(a)
จะต้องส่งคืนtrue
ด้วย - การผ่านผ่าน: ถ้า
a.equals(b)
มันส่งคืนtrue
และb.equals(c)
ส่งคืนด้วยtrue
จะc.equals(a)
ต้องส่งคืนtrue
ด้วย - ความสอดคล้อง: การเรียกเมธอดซ้ำๆ
equals()
จะต้องส่งคืนค่าเดียวกันตราบใดที่ค่าคุณสมบัติของออบเจ็กต์บางส่วนไม่เปลี่ยนแปลง นั่นคือหากวัตถุสองชิ้นเท่ากันใน Java วัตถุทั้งสองจะเท่ากันตราบใดที่คุณสมบัติของวัตถุยังคงไม่เปลี่ยนแปลง - การเปรียบเทียบ
null
: วัตถุจะต้องได้รับการตรวจnull
สอบ หากวัตถุมีค่าเท่ากับnull
วิธีการก็ควรส่งคืนfalse
ไม่ใช่NullPointerException
ตัวอย่างเช่นa.equals(null)
ควรส่งfalse
คืน
ข้อตกลงระหว่างเท่ากับและ hashCode ใน Java
- หากวัตถุมีค่าเท่ากันในผลลัพธ์ของการดำเนินการเมธอด วัตถุ
equals
นั้นhashcode
จะต้องเหมือนกัน - หากออบเจ็กต์ไม่เท่ากันในผลลัพธ์ของการดำเนินการเมธอด
equals
ก็hashcode
สามารถเหมือนกันหรือต่างกันก็ได้ อย่างไรก็ตาม เพื่อปรับปรุงประสิทธิภาพ ควรให้อ็อบเจ็กต์ที่แตกต่างกันส่งคืนโค้ดที่แตกต่างกันจะดีกว่า
วิธีแทนที่วิธีเท่ากับใน Java
-
@Override public boolean equals(Object obj) { /*1. Check*/
if (obj == this) { /*and return */ return true; }
-
Проверьте an object на
null
, а также проверьте, чтобы an objectы были одного типа. Не делайте проверку с помощьюinstanceof
так How такая проверка будет возвращатьtrue
для подклассов и будет работать правильно только в случае если ваш класс объявлен Howimmutable
. Вместо этого можно использоватьgetClass()
;if (obj == null || obj.getClass() != this.getClass()) { return false; }
-
Объявите переменную типа, который вы сравниваете, и приведите
obj
к этому типу. Потом сравнивайте каждый атрибут типа начиная с численных атрибутов (если имеются) потому что численные атрибуты проверяются быстрей. Сравнивайте атрибуты с помощью операторов И и ИЛИ (так называемыеshort-circuit logical operators
) для объединения проверок с другими атрибутами.Person guest = (Person) obj; return id == guest.id && (firstName == guest.firstName || (firstName != null && firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName || (lastName != null && lastName .equals(guest.getLastName()))); }
/** * Person class with equals and hashcode implementation in Java * @author Javin Paul */
public class Person {
private int id;
private String firstName;
private String lastName;
public int getId() { return id; }
public void setId(int id) { this.id = id;}
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
Person guest = (Person) obj;
return id == guest.id
&& (firstName == guest.firstName
|| (firstName != null &&firstName.equals(guest.getFirstName()))) && (lastName == guest.lastName
|| (lastName != null && lastName .equals(guest.getLastName())
));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); result = prime * result + id; result = prime * result +
((lastName == null) ? 0 : lastName.hashCode()); return result;
}
}
Распространенные ошибки при переопределении equals в Java
-
Вместо того, чтобы переопределять метод
equals (Override)
программист перегружает его(Overload)
Синтаксис методаequals()
в классеObject
определен Howpublic boolean equals(Object obj)
, но многие программисты ненароком перегружают метод:public boolean equals(Person obj)
- instead ofObject
в качестве аргумента используют Name своего класса (напр. Person). Эту ошибку сложно обнаружить из-заstatic binding
. Таким образом, если вы вызовете этот метод для an object своего класса, то метод не просто скомпorруется, а даже сделает это корректно. Однако, если вы положите ваш an object в коллекцию, напримерArrayList
и вызовете методcontains()
, работа которого основана на методеequals()
, то методcontains
не сможет обнаружить ваш an object. -
При переопределении метода
equals()
не проверять наnull
переменные, что в конечном итоге заканчиваетсяNullPointerException
при вызовеequals()
. Ниже представлен корректный code.firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname));
-
Третья распространенная ошибка это не переопределять метод
hashCode()
, а толькоequals()
. Вы обязаны переопределять оба методаequals()
иhashCode()
в Java. МетодhashCode
используется вhash
-коллекциях(напримерHashSet
), и чем меньше будет коллизий (одинаковый code при разных an objectх) тем эффективнее эти коллекции будут работать с an objectми вашего класса. -
Последняя распространенная ошибка программистов в том, что при переопределении метода
equals()
не сохраняется соответствие между методамиequals()
иcompareTo()
, что является неформальным требованием для избежания хранения дубликатов вSet (SortedSet, TreeSet)
.
Подсказки How писать в Java метод equals
-
Большинство IDE такие How NetBeans, Eclipse и IntelliJ IDEA обеспечивают поддержку генерации методов
equals()
иhashCode()
. В Eclipse нажмите правую кнопку -> source ->generate equals()
иhashCode()
. -
Если в классе есть уникальный бизнес-ключ, то будет достаточно сделать проверку только на equalsство этих полей. Как в нашем примере “id” - уникальный номер для каждого Person.
-
При переопределении
hashCode()
в Java удостоверьтесь в использовании всех полей, что были использованы в методеequals()
. -
String
และคลาส wrapper เช่นInteger
และFloat
แทนที่Double
เมธอดequals()
แต่StringBuffer
ไม่ได้แทนที่ -
เมื่อใดก็ตามที่เป็นไปได้ ให้สร้างฟิลด์
immutable
โดยใช้final
ตัวแปรใน Java -
เมื่อเปรียบเทียบ
String
วัตถุ ให้ใช้equals()
. โอเปอเรเตอร์==
แทน -
วัตถุสองชิ้นที่มีความเท่าเทียมกันทางตรรกะ แต่โหลดจากวัตถุที่แตกต่างกัน
ClassLoader
ไม่สามารถเท่ากันได้ โปรดจำไว้ว่าการตรวจสอบด้วยgetClass()
จะกลับมาfalse
หากคลาสตัวโหลดแตกต่างออกไป -
ใช้
@Override
คำอธิบายประกอบในเมธอด .hashCode
เนื่องจากจะป้องกันข้อผิดพลาดเล็กๆ น้อยๆ เช่น ค่าที่ส่งคืนของint
. อย่างไรก็ตาม โปรแกรมเมอร์บางคนส่งlong
คืน
GO TO FULL VERSION