نادیده گرفتن متدهای برابر () و hashCode() در جاوا
Equals
و hashCode
متدهای اساسی هستند که در کلاس اعلام شده Object
و در کتابخانه های استاندارد جاوا موجود هستند. این روش еquals()
برای مقایسه اشیاء و hashCode
تولید یک کد عدد صحیح برای شی مورد استفاده قرار می گیرد. این روش ها به طور گسترده در کتابخانه های استاندارد جاوا هنگام درج و بازیابی اشیاء در HashMap
. این روش equal
همچنین برای اطمینان از اینکه فقط اشیاء منحصربهفرد در HashSet
سایر Set
پیادهسازیها ذخیره میشوند، و همچنین در هر مورد دیگری که اشیاء نیاز به مقایسه دارند، استفاده میشود. پیادهسازی پیشفرض متد equals()
در کلاس java.lang.Object
، ارجاعها را با آدرسهای حافظهای که متغیرها ذخیره میکنند مقایسه میکند و true
تنها در صورتی برمیگرداند که آدرسها مطابقت داشته باشند، به عبارت دیگر، متغیرها به همان شی اشاره میکنند. اگر انتظار دارید که مقایسه بر اساس منطق طبیعی یا منطق تجاری انجام شود، جاوا توصیه میکند که روشها equals()
و را باطل کنید. hashCode()
بسیاری از کلاس ها در کتابخانه های استاندارد جاوا آنها را باطل می کنند، به عنوان مثال کلاس String
لغو می شود equals
به طوری که true
اگر محتویات دو شی مورد مقایسه یکسان باشد، برمی گردد. کلاس wrapper Integer
روش را equal
برای انجام مقایسه عددی نادیده می گیرد و غیره. از آنجایی که جاوا برای مقایسه آنها و به متدهایی HashMap
نیز متکی است ، جاوا قوانین زیر را برای نادیده گرفتن این روش ها ارائه می دهد: HashTable
equals()
hashCode()
key
values
- انعکاس پذیری: جسم باید با خودش برابر باشد.
- متقارن: اگر
a.equals(b)
برمی گرددtrue
، پسb.equals(a)
باید نیز برگرددtrue
. - Transitivity: اگر
a.equals(b)
برمی گرددtrue
وb.equals(c)
همچنین برمی گرددtrue
، پسc.equals(a)
باید نیز برگرددtrue
. - سازگاری: فراخوانی های مکرر به یک متد
equals()
باید همان مقدار را برگردانند تا زمانی که برخی از مقادیر ویژگی شی تغییر نکرده باشند. یعنی اگر دو شی در جاوا با هم برابر باشند، تا زمانی که خصوصیات آنها بدون تغییر باقی بماند، برابر خواهند بود. - مقایسه
null
: شی باید بررسی شودnull
. اگر شی برابر باشدnull
، متد باید برگرددfalse
، نهNullPointerException
. مثلاًa.equals(null)
باید برگرددfalse
.
توافق بین برابر و هش کد در جاوا
- اگر اشیاء در نتایج اجرای متد برابر باشند
equals
،hashcode
باید یکسان باشند. - اگر اشیاء در نتایج اجرای متد برابر نباشند
equals
،hashcode
می توانند یکسان یا متفاوت باشند. با این حال، برای بهبود عملکرد، بهتر است که اشیاء مختلف کدهای متفاوتی را برگردانند.
نحوه نادیده گرفتن متد برابر در جاوا
-
@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
override نمی کند. -
در صورت امکان، فیلدهایی را
immutable
با استفاده ازfinal
متغیرهای جاوا ایجاد کنید. -
هنگام مقایسه
String
اشیا،equals()
به جای آن از عملگر . استفاده کنید==
. -
دو شی که از نظر منطقی با هم برابر هستند اما از اشیاء مختلف بارگیری می شوند
ClassLoader
نمی توانند برابر باشند. به یاد داشته باشید که اگر کلاس لودر متفاوت باشد، بررسی باgetClass()
باز خواهد گشت .false
-
@Override
از حاشیه نویسی در روش . نیز استفاده کنیدhashCode
، زیرا از خطاهای ظریفی مانند مقدار بازگشتی جلوگیری میint
کندlong
.
GO TO FULL VERSION