JavaRush /Blog Java /Random-ES /Trabajar con los métodos hashCode() y equals() en Java
Lenchik854
Nivel 0
Chernihiv

Trabajar con los métodos hashCode() y equals() en Java

Publicado en el grupo Random-ES
En esta publicación describiré mi comprensión de los métodos hashCode()y equals(). Quiero hablar sobre su implementación predeterminada, así como también sobre cómo anularlas correctamente. También escribiré sobre la implementación de estos métodos utilizando las clases auxiliares del paquete Apache Common. Trabajar con métodos hashCode() y equals() en Java - 1Contenido de esta publicación:
  1. Usando hashCode()y equals().
  2. Anular el comportamiento predeterminado.
  3. Anulación hashCode()y equals()uso de Apache Commons Lang.
  4. Algo que es importante recordar.
  5. Atención especial al utilizar ORM.
Los métodos hashCode()y equals()se definieron en la clase Object, que es la clase principal de los objetos java. Por lo tanto, todos los objetos Java heredan la implementación predeterminada de estos métodos.

Usando hashCode() y es igual()

El método hashCode()se utiliza para obtener un número entero único para un objeto determinado. Cuando un objeto necesita almacenarse como una estructura de datos en una tabla hash (también llamada depósito), este número se utiliza para determinar su ubicación en esa tabla. De forma predeterminada, el método hashCode()de un objeto devuelve el número de la ubicación de memoria donde está almacenado el objeto. El método equals(), como su nombre indica, se utiliza para comprobar simplemente la igualdad de dos objetos. La implementación predeterminada de este método simplemente verifica las referencias de dos objetos para ver si son equivalentes.

Anular el comportamiento predeterminado

Todo funciona bien siempre y cuando no anules ninguno de estos métodos en tus clases. Pero a veces las aplicaciones necesitan cambiar el comportamiento predeterminado de algunos objetos. Tomemos un ejemplo en el que tienes un Employee. Escribamos la estructura mínima posible de dicha clase.
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;
    }
}
La clase descrita anteriormente Employeetiene algunos atributos básicos y métodos de acceso. Ahora veamos una situación simple en la que necesitamos comparar dos objetos de la clase 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));
    }
}
No hace falta ser clarividente para adivinar que el método anterior devolverá "falso". ¿Pero es esto realmente correcto, dado que estos dos objetos son iguales? En una aplicación en tiempo real, el método debe devolver verdadero. Para lograr el comportamiento correcto, debemos anular el método equals(), como se hace a continuación:
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());
}
Agregue este método a su clase Employeey la verificación de equivalencia devolverá "verdadero". Sin embargo, ¿hemos hecho todo? Aún no. Probemos nuestra clase modificada de una manera más.
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);
        //Печатает два un objetoа
        System.out.println(employees);
    }
}
El comando System.out.println(employee)imprime dos objetos. Si ambos objetos fueran equivalentes y Setsolo estuvieran contenidos objetos únicos, entonces HashSetdebería haber solo una instancia dentro, es decir. ambos objetos se refieren a las mismas instancias de la clase Employee. ¿Qué nos hemos perdido? Nos perdimos el segundo método importante hashCode(). Como dice la documentación de Java, si anula el método equals(), entonces deberá anular el método hashCode(). Entonces agreguemos otro método a nuestra clase Employee.
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
Agregamos este método una vez a nuestra clase y solo se imprimirá un objeto y, por lo tanto, la verificación de la equivalencia de e1 y e2 resultó verdadera.

Anulación hashCode()y equals()uso de Apache Commons Lang

Apache Commons proporciona dos excelentes clases auxiliares para llamar a métodos hashCode()y equals(). A continuación vemos el 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 otro lado, si utiliza uno de los editores de código, también deberían poder crear algunas estructuras interesantes para usted. Por ejemplo, si en el IDE de Eclipse haces clic derecho en clase >> fuente > Generando hashCode() y es igual()... generará una implementación muy buena para ti. Trabajar con los métodos hashCode() y equals() en Java - 2Algo que es importante recordar.
  1. Utilice siempre los mismos atributos de objeto para llamar a ambos y hashCode()y equals(). Sólo en nuestro caso usamos employee id.
  2. El método equals()debe ser persistente (si el objeto no ha cambiado, el método debe devolver el mismo valor).
  3. Siempre a.equals(b), entonces a.hashCode()debe ser igual que b.hashCode().
  4. Si anula un método, debe anular el segundo.

Atención especial al utilizar ORM

Si está tratando con ORM (ru.wikipedia.org/wiki/ORM), utilice siempre captadores y nunca utilice referencias de campo hashCode(). equals()Esto se debe a que en un ORM, de vez en cuando los campos se cargan mediante carga diferida y no son accesibles hasta que se llama a sus captadores. Por ejemplo, en nuestra clase Employeeusamos e1.id == e2.id. Es muy posible que los icampos d se carguen mediante carga diferida. Uno de los campos puede ser 0 o nulo y obtendremos un comportamiento incorrecto. Pero, si se usa e1.getId() == e2.getId(), podemos estar seguros incluso si los campos se cargaron mediante carga diferida; llamar al captador llenará el campo primero. Eso es todo lo que sé sobre los métodos hashCode()y equals(). Espero que esto ayude a alguien en alguna parte. ¡¡Buena suerte con sus estudios!! PD: Este es mi primer intento de traducción. Intenté transmitir todo lo más cerca posible de lo que el autor quería decir. Si tiene algún comentario, escriba en los comentarios. No juzgues estrictamente :-))) Artículo original
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION