Overriding equals() and hashCode() methods in Java
Equals
and hashCode
are the fundamental methods declared in the class Object
and contained in the standard Java libraries. The method еquals()
is used to compare objects and hashCode
to generate an integer code for the object. These methods are widely used in the Java standard libraries when inserting and retrieving objects in HashMap
. The method equal
is also used to ensure that only unique objects are stored in HashSet
other Set
implementations, as well as in any other cases where objects need to be compared. The default implementation of the method equals()
in the class java.lang.Object
compares references to the memory addresses that the variables store and returns true
only if the addresses match, in other words, the variables refer to the same object. Java recommends overriding the equals()
and methods hashCode()
if you expect the comparison to be done according to natural logic or business logic. Many classes in the standard Java libraries override them, for example the class String
overrides equals
so that it returns true
if the contents of the two objects being compared are the same. The wrapper class overrides Integer
the method equal
to perform a numerical comparison, and so on. Since Java HashMap
also relies on and methods to compare their and , Java offers the following rules for overriding these methods: HashTable
equals()
hashCode()
key
values
- Reflexivity: The object must be equal to itself.
- Symmetrical: if
a.equals(b)
it returnstrue
, thenb.equals(a)
it must also returntrue
. - Transitivity: if
a.equals(b)
it returnstrue
andb.equals(c)
also returnstrue
, thenc.equals(a)
it must also returntrue
. - Consistency: Repeated calls to a method
equals()
must return the same value as long as some of the object's property values are not changed. That is, if two objects are equal in Java, then they will be equal as long as their properties remain unchanged. - Comparison
null
: The object must be checked fornull
. If the object is equal tonull
, then the method should returnfalse
, notNullPointerException
. For example,a.equals(null)
it should returnfalse
.
Agreement between equals and hashCode in Java
- If the objects are equal in the results of method execution
equals
, then theyhashcode
must be the same. - If the objects are not equal in the results of method execution
equals
, then theyhashcode
can be either the same or different. However, to improve performance, it is better to have different objects return different codes.
How to override equals method 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
and wrapper classes such asInteger
,Float
andDouble
override the methodequals()
, butStringBuffer
does not override. -
Whenever possible, make fields
immutable
usingfinal
variables in Java. -
When comparing
String
objects, useequals()
the . operator instead==
. -
Two objects that are logically equal but loaded from different objects
ClassLoader
cannot be equal. Remember that checking withgetClass()
will returnfalse
if the loader class is different. -
Use
@Override
the annotation also on the . methodhashCode
, as this prevents subtle errors such as the return value of theint
. However, some programmers returnlong
.