JavaRush /Blogue Java /Random-PT /Trabalhando com métodos hashCode() e equals() em Java
Lenchik854
Nível 0
Chernihiv

Trabalhando com métodos hashCode() e equals() em Java

Publicado no grupo Random-PT
Neste post vou descrever minha compreensão dos métodos hashCode()e equals(). Quero falar sobre sua implementação padrão e também como substituí-los corretamente. Também escreverei sobre a implementação desses métodos usando as classes auxiliares do pacote Apache Common. Trabalhando com métodos hashCode() e equals() em Java - 1Conteúdo desta postagem:
  1. Usando hashCode()e equals().
  2. Substitua o comportamento padrão.
  3. Substituindo hashCode()e equals()usando Apache Commons Lang.
  4. Algo que é importante lembrar.
  5. Atenção especial ao usar ORM.
Os métodos hashCode()e equals()foram definidos na classe Object, que é a classe pai dos objetos Java. Portanto, todos os objetos Java herdam a implementação padrão desses métodos.

Usando hashCode() e equals()

O método hashCode()é usado para obter um número inteiro exclusivo para um determinado objeto. Quando um objeto precisa ser armazenado como uma estrutura de dados em uma tabela hash (também chamada de bucket), esse número é usado para determinar sua localização nessa tabela. Por padrão, o método hashCode()para um objeto retorna o número do local da memória onde o objeto está armazenado. O método equals(), como o próprio nome sugere, é usado simplesmente para verificar a igualdade de dois objetos. A implementação padrão deste método simplesmente verifica as referências de dois objetos para ver se são equivalentes.

Substituindo o comportamento padrão

Tudo funciona bem, desde que você não substitua nenhum desses métodos em suas classes. Mas às vezes os aplicativos precisam alterar o comportamento padrão de alguns objetos. Vamos dar um exemplo onde você tem um arquivo Employee. Vamos escrever a estrutura mínima possível de tal classe.
public class Employee
{
    private Integer id;
    private String firstname;
    private String lastName;
    private String department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer 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;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
}
A classe descrita acima Employeepossui alguns atributos básicos e métodos acessadores. Agora vamos ver uma situação simples onde precisamos comparar dois objetos da classe Employee.
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Печатает false в консоли
        System.out.println(e1.equals(e2));
    }
}
Não é preciso ser um clarividente para adivinhar que o método escrito acima retornará “falso”. Mas isso é realmente correto, visto que esses dois objetos são iguais? Na aplicação em tempo real, o método deve retornar verdadeiro. Para obter o comportamento correto, precisamos sobrescrever o método equals(), conforme feito abaixo:
public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
           return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
}
Adicione este método à sua classe Employeee a verificação de equivalência retornará “true”. Porém, fizemos tudo? Ainda não. Vamos testar nossa classe modificada de mais uma maneira.
import java.util.HashSet;
import java.util.Set;

public class EqualsTest
{
    public static void main(String[] args)
    {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);

        //Печатает 'true'
        System.out.println(e1.equals(e2));

        Set employees = new HashSet();
        employees.add(e1);
        employees.add(e2);
        //Печатает два an object
        System.out.println(employees);
    }
}
O comando System.out.println(employee)imprime dois objetos. Se ambos os objetos fossem equivalentes e Setapenas objetos únicos estivessem contidos, então HashSetdeveria haver apenas uma instância dentro, ou seja, ambos os objetos referem-se às mesmas instâncias da classe Employee. O que perdemos? Perdemos o segundo método importante hashCode(). Como diz a documentação do Java, se você substituir o método equals(), será necessário substituí-lo hashCode(). Então, vamos adicionar outro método à nossa classe Employee.
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
Adicionamos este método uma vez à nossa classe, e apenas um objeto será impresso, e assim, a verificação da equivalência de e1 e e2 mostrou-se verdadeira.

Substituindo hashCode()e equals()usando Apache Commons Lang

O Apache Commons fornece duas excelentes classes auxiliares para chamar métodos hashCode()e equals(). Abaixo vemos o uso:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
 private Integer id;
 private String firstname;
 private String lastName;
 private String department;
public Integer getId() {
    return id;
 }
 public void setId(Integer 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;
 }
 public String getDepartment() {
    return department;
 }
 public void setDepartment(String department) {
    this.department = department;
 }
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
           toHashCode();
 }
@Override
 public boolean equals(Object o) {
    if (o == null)
       return false;
    if (o == this)
       return true;
    if (o.getClass() != getClass())
       return false;
    Employee e = (Employee) o;
       return new EqualsBuilder().
              append(getId(), e.getId()).
              isEquals();
    }
 }
Por outro lado, se você usar um dos editores de código, eles também deverão ser capazes de invocar algumas estruturas interessantes para você. Por exemplo, se no IDE Eclipse você clicar com o botão direito em class >> source > Generating hashCode() and equals() ... isso irá gerar uma implementação muito bacana para você. Trabalhando com métodos hashCode() e equals() em Java - 2Algo que é importante lembrar.
  1. Sempre use os mesmos atributos de objeto para chamar and hashCode()e equals(). Apenas no nosso caso, usamos employee id.
  2. O método equals()deve ser persistente (se o objeto não foi alterado, o método deve retornar o mesmo valor).
  3. Sempre que a.equals(b), então a.hashCode()deve ser igual a b.hashCode().
  4. Se você substituir um método, deverá substituir o segundo.

Atenção especial ao usar ORM

Se você estiver lidando com ORM (ru.wikipedia.org/wiki/ORM), sempre use getters e nunca use referências de campo hashCode(). equals()Isso ocorre porque em um ORM, de tempos em tempos, os campos são carregados usando carregamento lento e não ficam acessíveis até que seus getters sejam chamados. Por exemplo, em nossa classe Employee, usamos e1.id == e2.id. É perfeitamente possível que os icampos d sejam carregados usando carregamento lento. Um dos campos pode ser 0 ou nulo e obteremos um comportamento incorreto. Mas, se for usado e1.getId() == e2.getId(), podemos ter certeza mesmo que os campos tenham sido carregados usando carregamento lento; chamar o getter preencherá o campo primeiro. Isso é tudo que sei sobre os métodos hashCode()and equals(). Espero que isso ajude alguém em algum lugar. Boa sorte com seus estudos!! ps Esta é minha primeira tentativa de tradução. Tentei transmitir tudo o mais próximo possível do que o autor queria dizer. Se você tiver algum comentário, por favor escreva nos comentários. Não julgue estritamente :-))) Artigo original
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION