Por que é importante redefinir os métodos equals e hashCode em Java?
sobes.tech IA
Resposta da IA
A sobrescrita de equals e hashCode é importante para o funcionamento correto com objetos em coleções e na comparação.
- Simetria: Se
a.equals(b)retornatrue, entãob.equals(a)também deve retornartrue. - Reflexividade: Para qualquer objeto não nulo
a,a.equals(a)deve retornartrue. - Transitividade: Se
a.equals(b)eb.equals(c)retornamtrue, entãoa.equals(c)também deve retornartrue. - Consistência: Múltiplas invocações de
a.equals(b)devem retornar de forma consistentetrueoufalse, desde que as informações usadas nas comparações deequalsnão sejam modificadas.
Para hashCode:
- Consistência: Se a informação usada nas comparações de
equalsno objeto não foi modificada, as múltiplas chamadas ahashCodeno objeto devem retornar o mesmo valor inteiro. - Ligação com
equals: Se dois objetos são iguais de acordo com o métodoequals, então a chamada ahashCodeem cada um dos objetos não iguais deve retornar o mesmo valor inteiro. - Otimização: Não é necessário que, se dois objetos não forem iguais de acordo com
equals, a chamada ahashCodeem cada um deles retorne resultados inteiros diferentes. No entanto, gerar códigos hash diferentes para objetos não iguais pode melhorar o desempenho das tabelas hash.
O não cumprimento destas regras leva a um comportamento imprevisível ao usar coleções como HashSet, HashMap, ArrayList e outras, que dependem de uma implementação correta desses métodos para determinar a igualdade dos objetos e a sua colocação.
Por exemplo:
// Classe de exemplo sem `equals` e `hashCode` corretos
class PersonBroken {
private String name;
private int age;
public PersonBroken(String name, int age) {
this.name = name;
this.age = age;
}
// getters omitidos por brevidade
}
// Classe de exemplo com `equals` e `hashCode` corretos
class PersonCorrect {
private String name;
private int age;
public PersonCorrect(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PersonCorrect that = (PersonCorrect) o;
return age == that.age &&
Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
// getters omitidos por brevidade
}
// Uso em coleção
List<PersonBroken> brokenList = new ArrayList<>();
brokenList.add(new PersonBroken("Alice", 30));
System.out.println(brokenList.contains(new PersonBroken("Alice", 30))); // Provavelmente false
List<PersonCorrect> correctList = new ArrayList<>();
correctList.add(new PersonCorrect("Alice", 30));
System.out.println(correctList.contains(new PersonCorrect("Alice", 30))); // Provavelmente true
Set<PersonBroken> brokenSet = new HashSet<>();
brokenSet.add(new PersonBroken("Bob", 25));
brokenSet.add(new PersonBroken("Bob", 25));
System.out.println(brokenSet.size()); // Provavelmente 2
Set<PersonCorrect> correctSet = new HashSet<>();
correctSet.add(new PersonCorrect("Bob", 25));
correctSet.add(new PersonCorrect("Bob", 25));
System.out.println(correctSet.size()); // Provavelmente 1
No exemplo com PersonBroken, objetos com os mesmos valores de campos são considerados diferentes nas coleções, pois usam as implementações padrão de equals (compara referências) e hashCode (gera pelo endereço do objeto). No exemplo com PersonCorrect, os métodos sobrescritos permitem às coleções determinar corretamente a equivalência de objetos com base no seu conteúdo.