Zastępowanie metod równości() i hashCode() w Javie
Equals
i hashCode
są podstawowymi metodami zadeklarowanymi w klasie Object
i zawartymi w standardowych bibliotekach Java. Metoda еquals()
służy do porównywania obiektów i hashCode
generowania kodu całkowitego dla obiektu. Metody te są szeroko stosowane w standardowych bibliotekach Java podczas wstawiania i pobierania obiektów w plikach HashMap
. Metodę tę equal
stosuje się również w celu zapewnienia, że w HashSet
innych Set
implementacjach przechowywane są tylko unikalne obiekty, a także we wszystkich innych przypadkach, gdy zachodzi potrzeba porównania obiektów. Domyślna implementacja metody equals()
w klasie java.lang.Object
porównuje odniesienia do adresów pamięci przechowywanych przez zmienne i zwraca true
tylko wtedy, gdy adresy są zgodne, innymi słowy zmienne odnoszą się do tego samego obiektu. Java zaleca zastąpienie metod equals()
i hashCode()
, jeśli oczekujesz, że porównanie zostanie wykonane zgodnie z logiką naturalną lub logiką biznesową. Wiele klas w standardowych bibliotekach Java zastępuje je, na przykład klasa String
zastępuje je equals
w taki sposób, że zwraca, true
jeśli zawartość dwóch porównywanych obiektów jest taka sama. Klasa opakowania zastępuje Integer
metodę equal
w celu przeprowadzenia porównania numerycznego i tak dalej. Ponieważ Java HashMap
również opiera się na metodach i do porównywania ich i , Java oferuje następujące reguły zastępowania tych metod: HashTable
equals()
hashCode()
key
values
- Zwrotność: Obiekt musi być równy sobie.
- Symetryczny: jeśli
a.equals(b)
zwrócitrue
, tob.equals(a)
musi również wrócićtrue
. - Przechodniość: jeśli
a.equals(b)
zwracatrue
ib.equals(c)
zwraca równieżtrue
, toc.equals(a)
musi również powrócićtrue
. - Spójność: Powtarzające się wywołania metody
equals()
muszą zwracać tę samą wartość, o ile niektóre wartości właściwości obiektu nie ulegną zmianie. Oznacza to, że jeśli dwa obiekty w Javie są równe, to będą takie same, o ile ich właściwości pozostaną niezmienione. - Porównanie
null
: Należy sprawdzić obiektnull
. Jeśli obiekt jest równynull
, to metoda powinna zwrócićfalse
, a nieNullPointerException
. Na przykłada.equals(null)
powinien wrócićfalse
.
Umowa pomiędzy równymi i hashCode w Javie
- Jeżeli obiekty w wynikach wykonania metody są sobie równe
equals
, tohashcode
muszą być takie same. - Jeśli obiekty nie są równe w wynikach wykonania metody
equals
, tohashcode
mogą być takie same lub różne. Aby jednak poprawić wydajność, lepiej jest, aby różne obiekty zwracały różne kody.
Jak zastąpić metodę równości w Javie
-
@Override public boolean equals(Object obj) { /*1. Sprawdzać*/
if (obj == this) { /*i powrót */ return true; }
-
Sprawdź obiekt pod kątem
null
, a także sprawdź, czy obiekty są tego samego typu. Nie sprawdzaj,instanceof
ponieważ zwróci totrue
dla podklas i będzie działać poprawnie tylko wtedy, gdy twoja klasa zostanie zadeklarowana jakoimmutable
. Możesz użyć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
определен Jakpublic boolean equals(Object obj)
, но многие программисты ненароком перегружают метод:public boolean equals(Person obj)
- zamiastObject
в качестве аргумента используют Nazwa своего класса (напр. Person). Эту ошибку сложно обнаружить из-заstatic binding
. Таким образом, если вы вызовете этот метод для obiektа своего класса, то метод не просто скомпLubруется, а даже сделает это корректно. Однако, если вы положите ваш obiekt в коллекцию, напримерArrayList
и вызовете методcontains()
, работа которого основана на методеequals()
, то методcontains
не сможет обнаружить ваш obiekt. -
При переопределении метода
equals()
не проверять наnull
переменные, что в конечном итоге заканчиваетсяNullPointerException
при вызовеequals()
. Ниже представлен корректный kod.firstname == guest.firstname || (firstname != null && firstname.equals(guest.firstname));
-
Третья распространенная ошибка это не переопределять метод
hashCode()
, а толькоequals()
. Вы обязаны переопределять оба методаequals()
иhashCode()
в Java. МетодhashCode
используется вhash
-коллекциях(напримерHashSet
), и чем меньше будет коллизий (одинаковый kod при разных obiektах) тем эффективнее эти коллекции будут работать с obiektами вашего класса. -
Последняя распространенная ошибка программистов в том, что при переопределении метода
equals()
не сохраняется соответствие между методамиequals()
иcompareTo()
, что является неформальным требованием для избежания хранения дубликатов вSet (SortedSet, TreeSet)
.
Подсказки Jak писать в Java метод equals
-
Большинство IDE такие Jak NetBeans, Eclipse и IntelliJ IDEA обеспечивают поддержку генерации методов
equals()
иhashCode()
. В Eclipse нажмите правую кнопку -> source ->generate equals()
иhashCode()
. -
Если в классе есть уникальный бизнес-ключ, то будет достаточно сделать проверку только на równa sięство этих полей. Как в нашем примере “id” - уникальный номер для каждого Person.
-
При переопределении
hashCode()
в Java удостоверьтесь в использовании всех полей, что были использованы в методеequals()
. -
String
и классы-оболочки такие JakInteger
,Float
иDouble
переопределяют методequals()
, ноStringBuffer
не переопределяет. -
При любой возможности делайте поля
immutable
используяfinal
переменные в Java. -
При сравнении
String
obiektов используйтеequals()
zamiast оператора==
. -
Dwa obiekty, które są logicznie równe, ale załadowane z różnych obiektów,
ClassLoader
nie mogą być równe. Pamiętaj, że sprawdzenie za pomocągetClass()
zwrócifalse
, jeśli klasa programu ładującego jest inna. -
Użyj
@Override
adnotacji również w metodzie .hashCode
, ponieważ zapobiega to subtelnym błędom, takim jak wartość zwracana przezint
. Jednakże niektórzy programiści zwracająlong
.
GO TO FULL VERSION