עקיפה של שיטות equals() ו-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
.
הסכם בין equals ו-hashCode ב-Java
- אם האובייקטים שווים בתוצאות של ביצוע השיטה
equals
, אז הםhashcode
חייבים להיות זהים. - אם האובייקטים אינם שווים בתוצאות של ביצוע השיטה
equals
, אז הםhashcode
יכולים להיות זהים או שונים. עם זאת, כדי לשפר את הביצועים, עדיף שאובייקטים שונים יחזירו קודים שונים.
Как переопределять метод equals в 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
ומחלקות עטיפה כגוןInteger
,Float
ודרוסDouble
את השיטהequals()
, אךStringBuffer
אינו עוקף. -
במידת האפשר, צור שדות
immutable
באמצעותfinal
משתנים ב-Java. -
בעת השוואת
String
אובייקטים, השתמשequals()
במקום זאת באופרטור==
. -
שני אובייקטים שווים מבחינה לוגית אך נטענים מאובייקטים שונים
ClassLoader
אינם יכולים להיות שווים. זכור שבדיקה עםgetClass()
תחזורfalse
אם מחלקת הטעינה שונה. -
השתמש
@Override
בהערה גם בשיטת .hashCode
, שכן הדבר מונע שגיאות עדינות כמו ערך ההחזרה של ה-int
. עם זאת, חלק מהמתכנתים מחזיריםlong
.
GO TO FULL VERSION