Sostituzione dei metodi equals() e hashCode() in Java
Equals
e hashCode
sono i metodi fondamentali dichiarati nella classe Object
e contenuti nelle librerie Java standard. Il metodo еquals()
viene utilizzato per confrontare oggetti e hashCode
generare un codice intero per l'oggetto. Questi metodi sono ampiamente utilizzati nelle librerie standard Java durante l'inserimento e il recupero di oggetti in file HashMap
. Il metodo equal
viene utilizzato anche per garantire che solo oggetti univoci vengano archiviati in HashSet
altre Set
implementazioni, nonché in tutti gli altri casi in cui è necessario confrontare gli oggetti. L'implementazione predefinita del metodo equals()
nella classe java.lang.Object
confronta i riferimenti agli indirizzi di memoria che le variabili memorizzano e restituisce true
solo se gli indirizzi corrispondono, in altre parole, le variabili si riferiscono allo stesso oggetto. Java consiglia di sovrascrivere i metodi equals()
e hashCode()
se si prevede che il confronto segua la logica naturale o la logica aziendale. Molte classi nelle librerie Java standard le sovrascrivono, ad esempio la classe String
sovrascrive equals
in modo che restituisca true
se il contenuto dei due oggetti confrontati è lo stesso. La classe wrapper sovrascrive Integer
il metodo equal
per eseguire un confronto numerico e così via. Poiché Java si basa HashMap
anche sui metodi e per confrontare i rispettivi e , Java offre le seguenti regole per sovrascrivere questi metodi: HashTable
equals()
hashCode()
key
values
- Riflessività: l'oggetto deve essere uguale a se stesso.
- Simmetrico: se
a.equals(b)
ritornatrue
, allorab.equals(a)
deve tornare anchetrue
. - Transitività: se
a.equals(b)
ritornatrue
eb.equals(c)
ritorna anchetrue
, allorac.equals(a)
deve ritornare anchetrue
. - Coerenza: le chiamate ripetute a un metodo
equals()
devono restituire lo stesso valore purché alcuni valori delle proprietà dell'oggetto non vengano modificati. Cioè, se due oggetti sono uguali in Java, allora saranno uguali finché le loro proprietà rimarranno invariate. - Confronto
null
: L'oggetto deve essere controllatonull
. Se l'oggetto è uguale anull
, il metodo dovrebbe restituirefalse
, nonNullPointerException
. Ad esempio,a.equals(null)
dovrebbe restituirefalse
.
Accordo tra equals e hashCode in Java
- Se gli oggetti sono uguali nei risultati dell'esecuzione del metodo
equals
, allorahashcode
devono essere gli stessi. - Se gli oggetti non sono uguali nei risultati dell'esecuzione del metodo
equals
,hashcode
possono essere uguali o diversi. Tuttavia, per migliorare le prestazioni, è preferibile che oggetti diversi restituiscano codici diversi.
Come sovrascrivere il metodo equals in 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
e classi wrapper comeInteger
,Float
eDouble
sovrascrivono il metodoequals()
, maStringBuffer
non sovrascrivono. -
Quando possibile, crea campi
immutable
utilizzandofinal
variabili in Java. -
Quando confronti
String
gli oggetti, utilizzaequals()
invece l'operatore==
. -
Due oggetti logicamente uguali ma caricati da oggetti diversi
ClassLoader
non possono essere uguali. Ricorda che il controllo congetClass()
restituiràfalse
se la classe del caricatore è diversa. -
Utilizzare
@Override
l'annotazione anche sul metodo .hashCode
, in quanto ciò impedisce errori sottili come il valore restituito del metodoint
.Tuttavia, alcuni programmatori restituisconolong
.
GO TO FULL VERSION