Por que e como sobrescrever o método hashCode?
sobes.tech IA
Resposta da IA
O método hashCode é usado para obter o código de hash inteiro de um objeto. É necessário para o funcionamento correto de coleções baseadas em tabelas de hash, como HashMap, HashSet e HashTable. Quando um objeto é adicionado a tal coleção, seu código de hash é usado para determinar a "cesta" (bucket) onde o objeto será colocado. Ao procurar um objeto, o código de hash é recalculado para identificar rapidamente a cesta a ser examinada.
É necessário sobrescrever hashCode se você sobrescrever o método equals. De acordo com o contrato entre equals e hashCode:
- Se dois objetos são iguais segundo
equals, seus códigos de hash, retornados porhashCode, devem ser iguais. - Se dois objetos não são iguais segundo
equals, seus códigos de hash não precisam ser diferentes, mas para melhor desempenho das coleções, seria preferível que fossem.
Se você sobrescrever equals sem sobrescrever hashCode, objetos iguais terão códigos de hash diferentes (exceto coincidências aleatórias), o que levará a um funcionamento incorreto das coleções:
- Objetos considerados iguais por
equalsserão colocados em cestas diferentes. - A busca por um objeto igual pode falhar, pois apenas uma cesta determinada pelo código de hash do objeto buscado será verificada.
Para sobrescrever hashCode, geralmente combina-se o código de hash dos campos do objeto que participam na comparação de igualdade em equals.
As formas mais comuns de sobrescrever:
-
Uso de
Objects.hash()(desde Java 7): A forma mais simples e recomendada. É segura paranulle usa os códigos de hash dos campos fornecidos.// Exemplo de uso de Objects.hash() import java.util.Objects; public class MyClass { private int field1; private String field2; // ... construtor, getters, setters @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyClass myClass = (MyClass) o; return field1 == myClass.field1 && Objects.equals(field2, myClass.field2); } @Override public int hashCode() { return Objects.hash(field1, field2); // Passa os campos que participam em equals } } -
Manual (usando um algoritmo simples): Abordagem de baixo nível, que pode ser útil para compreensão, mas mais propensa a erros. Normalmente usa multiplicação e soma simples.
// Exemplo de sobrescrita manual de hashCode public class MyClass { private int field1; private String field2; // ... construtor, getters, setters @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; MyClass myClass = (MyClass) o; return field1 == myClass.field1 && Objects.equals(field2, myClass.field2); } @Override public int hashCode() { int result = 17; // Valor inicial (qualquer número ímpar) result = 31 * result + field1; // Multiplicamos por um número primo ímpar (31 é padrão) e adicionamos o hash do campo result = 31 * result + (field2 != null ? field2.hashCode() : 0); // Tratamento de null para objetos return result; } }
O número primo ímpar padrão (31) é usado porque a multiplicação por 31 pode ser otimizada pelo compilador (31 * i == (i << 5) - i).
- Uso de IDE: A maioria das IDEs modernas (IntelliJ IDEA, Eclipse) possui funções para gerar automaticamente os métodos
equals()ehashCode(). Essa é a abordagem mais segura e recomendada, pois elas geram código de acordo com as melhores práticas.
O principal objetivo de sobrescrever hashCode é garantir que objetos iguais tenham códigos de hash iguais, o que é fundamental para o funcionamento correto de coleções baseadas em hash.