Remplacement des méthodes equals() et hashCode() en Java
Equals
et hashCode
sont les méthodes fondamentales déclarées dans la classe Object
et contenues dans les bibliothèques Java standard. La méthode еquals()
est utilisée pour comparer des objets et hashCode
générer un code entier pour l'objet. Ces méthodes sont largement utilisées dans les bibliothèques standard Java lors de l'insertion et de la récupération d'objets dans HashMap
. La méthode equal
est également utilisée pour garantir que seuls les objets uniques sont stockés dans HashSet
d'autres Set
implémentations, ainsi que dans tout autre cas où des objets doivent être comparés. L'implémentation par défaut de la méthode equals()
dans la classe java.lang.Object
compare les références aux adresses mémoire stockées par les variables et ne renvoie true
que si les adresses correspondent, en d'autres termes, les variables font référence au même objet. Java recommande de remplacer les méthodes equals()
et hashCode()
si vous souhaitez que la comparaison soit effectuée selon la logique naturelle ou la logique métier. De nombreuses classes dans les bibliothèques Java standard les remplacent, par exemple la classe String
les remplace equals
afin qu'elle soit renvoyée true
si le contenu des deux objets comparés est le même. La classe wrapper remplace Integer
la méthode equal
pour effectuer une comparaison numérique, et ainsi de suite. Étant donné que Java s'appuie HashMap
également sur les méthodes and pour comparer leurs and , Java propose les règles suivantes pour remplacer ces méthodes : HashTable
equals()
hashCode()
key
values
- Réflexivité : L'objet doit être égal à lui-même.
- Symétrique : s'il
a.equals(b)
renvoietrue
, alorsb.equals(a)
il doit également renvoyertrue
. - Transitivité : si
a.equals(b)
elle renvoietrue
etb.equals(c)
renvoie égalementtrue
, alorsc.equals(a)
elle doit également renvoyertrue
. - Cohérence : les appels répétés à une méthode
equals()
doivent renvoyer la même valeur tant que certaines valeurs de propriétés de l'objet ne sont pas modifiées. Autrement dit, si deux objets sont égaux en Java, ils le seront tant que leurs propriétés restent inchangées. - Comparaison
null
: L'objet doit être vérifiénull
. Si l'objet est égal ànull
, alors la méthode doit renvoyerfalse
, et nonNullPointerException
. Par exemple,a.equals(null)
il devrait renvoyerfalse
.
Accord entre égaux et hashCode en Java
- Si les objets sont égaux dans les résultats de l’exécution de la méthode
equals
, alors ilshashcode
doivent être identiques. - Si les objets ne sont pas égaux dans les résultats de l’exécution de la méthode
equals
, ilshashcode
peuvent alors être identiques ou différents. Cependant, pour améliorer les performances, il est préférable que différents objets renvoient des codes différents.
Как переопределять метод 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
et des classes wrapper telles queInteger
,Float
etDouble
remplacent la méthodeequals()
, maisStringBuffer
ne remplacent pas. -
Dans la mesure du possible, créez des champs
immutable
à l'aidefinal
de variables en Java. -
Lorsque vous comparez
String
des objets, utilisezequals()
plutôt l'opérateur==
. -
Deux objets logiquement égaux mais chargés à partir d'objets différents
ClassLoader
ne peuvent pas être égaux. N'oubliez pas que la vérification avecgetClass()
sera renvoyéefalse
si la classe du chargeur est différente. -
Utilisez
@Override
également l'annotation sur la méthode .hashCode
, car cela évite des erreurs subtiles telles que la valeur de retour deint
. Cependant, certains programmeurs renvoientlong
.
GO TO FULL VERSION