JavaRush /Blog Java /Random-ES /Pausa para el café #168. ¿Por qué anular los métodos igua...

Pausa para el café #168. ¿Por qué anular los métodos iguales y de código hash en Java?

Publicado en el grupo Random-ES

¿Por qué anular los métodos iguales y de código hash en Java?

Fuente: Medio Este artículo se centra en dos métodos estrechamente relacionados: equals() y hashcode() . Aprenderá cómo interactúan entre sí y cómo anularlos correctamente. Pausa para el café #168.  ¿Por qué anular los métodos iguales y de código hash en Java?  - 1

¿Por qué anulamos el método equals()?

En Java, no podemos sobrecargar el comportamiento de operadores como == , += , -+ . Trabajan según un proceso determinado. Por ejemplo, considere la operación del operador == .

¿Cómo funciona el operador ==?

Comprueba si las dos referencias que se comparan apuntan a la misma instancia en la memoria. El operador == solo se evaluará como verdadero si las dos referencias representan la misma instancia en la memoria. Echemos un vistazo al código de muestra:
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
      }
Digamos que en su programa ha creado dos objetos Persona en diferentes lugares y desea compararlos.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println( person1 == person2 ); --> will print false!
Desde una perspectiva empresarial, los dos parecen iguales, ¿verdad? Pero para la JVM no son lo mismo. Dado que ambas se crean utilizando la nueva palabra clave , estas instancias se ubican en diferentes segmentos de memoria. Por lo tanto, el operador == devolverá false . Pero si no podemos anular el operador == , ¿cómo le decimos a la JVM que queremos que estos dos objetos sean tratados de la misma manera? Aquí es donde entra en juego el método .equals() . Puedes anular equals() para comprobar si algunos objetos tienen los mismos valores para ciertos campos para poder considerarlos iguales. Puede elegir qué campos comparar. Si decimos que dos objetos Persona serán iguales sólo si tienen la misma edad y el mismo nombre, entonces el IDE generará algo como esto para crear automáticamente iguales() :
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
Volvamos a nuestro ejemplo anterior.
Person person1 = new Person("Mike", 34);
Person person2 = new Person("Mike", 34);
System.out.println ( person1 == person2 ); --> will print false!
System.out.println ( person1.equals(person2) ); --> will print true!
Sí, no podemos sobrecargar el operador == para comparar objetos de la forma que queramos, pero Java nos ofrece otra forma: el método equals() , que podemos anular como queramos. Tenga en cuenta que si no proporcionamos nuestra versión personalizada de .equals() (también conocida como anulación) en nuestra clase, entonces el .equals() predefinido de la clase Objeto y el operador == se comportarán igual. El método equals() predeterminado , heredado de Object , verificará si ambas instancias que se comparan son iguales en la memoria.

¿Por qué anulamos el método hashCode()?

Algunas estructuras de datos en Java, como HashSet y HashMap , almacenan sus elementos en función de una función hash que se aplica a esos elementos. La función hash es hashCode() . Si tenemos la opción de anular el método .equals() , entonces también deberíamos tener la opción de anular el método hashCode() . Hay una razón para esto. Después de todo, la implementación predeterminada de hashCode() , heredada de Object , ¡considera que todos los objetos en la memoria son únicos! Pero volvamos a estas estructuras de datos hash. Existe una regla para estas estructuras de datos. Un HashSet no puede contener valores duplicados y un HashMap no puede contener claves duplicadas. Un HashSet se implementa utilizando un HashMap de tal manera que cada valor de HashSet se almacena como una clave en el HashMap . ¿Cómo funciona HashMap ? HashMap es una matriz nativa con múltiples segmentos. Cada segmento tiene una lista vinculada ( linkedList ). Esta lista vinculada almacena nuestras claves. HashMap encuentra la lista vinculada correcta para cada clave usando el método hashCode() y luego recorre en iteración todos los elementos de esa lista vinculada y aplica el método equals() a cada uno de esos elementos para verificar si ese elemento está contenido allí. No se permiten claves duplicadas. Pausa para el café #168.  ¿Por qué anular los métodos iguales y de código hash en Java?  - 2Cuando ponemos algo dentro de un HashMap , la clave se almacena en una de estas listas vinculadas. En qué lista vinculada se almacenará esta clave se muestra mediante el resultado del método hashCode() para esa clave. Es decir, si key1.hashCode() da como resultado 4, entonces esa clave1 se almacenará en el cuarto segmento de la matriz en LinkedList existente allí . De forma predeterminada, el método hashCode() devuelve resultados diferentes para cada instancia. Si tenemos un valor predeterminado igual () que se comporta como == , tratando todas las instancias en la memoria como objetos diferentes, entonces no habrá ningún problema. Como recordará, en nuestro ejemplo anterior dijimos que queremos que las instancias de Persona se consideren iguales si sus edades y nombres son los mismos.
Person person1 = new Person("Mike", 34);
    Person person2 = new Person("Mike", 34);
    System.out.println ( person1.equals(person2) );  --> will print true!
Ahora creemos un mapa para almacenar estas instancias como claves con una cadena específica como par de valores.
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
En la clase Persona , no hemos anulado el método hashCode , pero tenemos un método igual anulado . Dado que el hashCode predeterminado proporciona resultados diferentes para diferentes instancias Java de person1.hashCode() y person2.hashCode() , existen muchas posibilidades de obtener resultados diferentes. Nuestro mapa puede terminar con diferentes personas en diferentes listas enlazadas. Pausa para el café #168.  ¿Por qué anular los métodos iguales y de código hash en Java?  - 3Esto va en contra de la lógica de HashMap . Después de todo, ¡ un HashMap no puede tener varias claves idénticas! El punto es que el hashCode() predeterminado heredado de la clase Object no es suficiente. Incluso después de anular el método equals() de la clase Persona . Es por eso que tenemos que anular el método hashCode() después de anular el método igual . Ahora arreglemos esto. Necesitamos anular nuestro método hashCode() para que tenga en cuenta los mismos campos que equals() , es decir, edad y nombre .
public class Person {
      private Integer age;
      private String name;

      ..getters, setters, constructors
@Override
public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                name.equals(person.name);
    }
@Override
public int hashCode() {
        int prime = 31;
        return prime*Objects.hash(name, age);
    }
En el método hashCode() usamos un valor simple (puedes usar cualquier otro valor). Sin embargo, se sugiere utilizar números primos para crear menos problemas. Intentemos almacenar estas claves en nuestro HashMap nuevamente :
Map<Person, String> map = new HashMap();
map.put(person1, "1");
map.put(person2, "2");
person1.hashCode() y person2.hashCode() serán iguales. Digamos que son 0. El HashMap irá al segmento 0 y en él el LinkedList guardará a persona1 como clave con el valor “1”. En el segundo caso, cuando HashMap vuelva al depósito 0 para almacenar la clave persona2 con el valor “2”, verá que ya existe allí otra clave igual. De esta forma sobrescribirá la clave anterior. Y solo la clave person2 existirá en nuestro HashMap . ¡Así aprendimos cómo funciona la regla HashMap , que establece que no se pueden usar varias claves idénticas! Sin embargo, tenga en cuenta que las instancias desiguales pueden tener el mismo código hash y las instancias iguales deben devolver el mismo código hash.Pausa para el café #168.  ¿Por qué anular los métodos iguales y de código hash en Java?  - 4
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION