Substituindo os métodos equals() e hashCode() em Java
Equals
e hashCode
são os métodos fundamentais declarados na classe Object
e contidos nas bibliotecas Java padrão. O método еquals()
é usado para comparar objetos e hashCode
gerar um código inteiro para o objeto. Esses métodos são amplamente utilizados nas bibliotecas padrão Java ao inserir e recuperar objetos em arquivos HashMap
. O método equal
também é usado para garantir que apenas objetos únicos sejam armazenados em HashSet
outras Set
implementações, bem como em quaisquer outros casos onde os objetos precisem ser comparados. A implementação padrão do método equals()
na classe java.lang.Object
compara as referências aos endereços de memória que as variáveis armazenam e retorna true
apenas se os endereços corresponderem, ou seja, as variáveis se referem ao mesmo objeto. Java recomenda substituir os métodos equals()
e hashCode()
se você espera que a comparação seja feita de acordo com a lógica natural ou lógica de negócios. Muitas classes nas bibliotecas Java padrão as substituem, por exemplo, a classe String
substitui equals
para retornar true
se o conteúdo dos dois objetos que estão sendo comparados for o mesmo. A classe wrapper substitui Integer
o método equal
para realizar uma comparação numérica e assim por diante. Como Java HashMap
também depende de métodos e para comparar seus e , Java oferece as seguintes regras para substituir esses métodos: HashTable
equals()
hashCode()
key
values
- Reflexividade: O objeto deve ser igual a si mesmo.
- Simétrico: se
a.equals(b)
retornartrue
, entãob.equals(a)
também deverá retornartrue
. - Transitividade: se
a.equals(b)
retornartrue
eb.equals(c)
também retornartrue
, entãoc.equals(a)
também deverá retornartrue
. - Consistência: chamadas repetidas a um método
equals()
devem retornar o mesmo valor, desde que alguns valores das propriedades do objeto não sejam alterados. Ou seja, se dois objetos são iguais em Java, então eles serão iguais enquanto suas propriedades permanecerem inalteradas. - Comparação
null
: O objeto deve ser verificadonull
. Se o objeto for igual anull
, então o método deverá retornarfalse
, nãoNullPointerException
. Por exemplo,a.equals(null)
deve retornarfalse
.
Acordo entre iguais e hashCode em Java
- Se os objetos forem iguais nos resultados da execução do método
equals
, então eleshashcode
deverão ser iguais. - Se os objetos não forem iguais nos resultados da execução do método
equals
, eleshashcode
poderão ser iguais ou diferentes. No entanto, para melhorar o desempenho, é melhor que objetos diferentes retornem códigos diferentes.
Как переопределять метод 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
e classes wrapper comoInteger
,Float
eDouble
substituem o métodoequals()
, masStringBuffer
não substituem. -
Sempre que possível, crie campos
immutable
usandofinal
variáveis em Java. -
Ao comparar
String
objetos, useequals()
o operador==
. -
Dois objetos logicamente iguais, mas carregados de objetos diferentes,
ClassLoader
não podem ser iguais. Lembre-se de que a verificação comgetClass()
retornaráfalse
se a classe do carregador for diferente. -
Use
@Override
a anotação também no método .hashCode
, pois isso evita erros sutis, como o valor de retorno doint
.No entanto, alguns programadores retornamlong
.
GO TO FULL VERSION