Importancia del método Hashcode en Java

Requisito previo: métodos Equals() y hashCode() en Java

HashMap y HashSet usan hashing para manipular datos. Usan el método hashCode() para verificar los valores hash. La implementación predeterminada de hashCode() en la clase Object devuelve enteros distintos para diferentes objetos. A veces, tenemos que implementar el método hashCode en nuestro programa.
Considere el siguiente ejemplo

// Java puzzle to illustrate use
// of hashcode() and equals() method
import java.util.*;
public class Name {
    private final String first, last;
    public Name(String first, String last)
    {
        this.first = first;
        this.last = last;
    }
    public boolean equals(Object o)
    {
        if (!(o instanceof Name))
            return false;
        Name n = (Name)o;
        return n.first.equals(first) && n.last.equals(last);
    }
    public static void main(String[] args)
    {
        Set<Name> s = new HashSet<Name>();
        s.add(new Name("Shubham", "Juneja"));
        System.out.println(
            s.contains(new Name("Shubham", "Juneja")));
    }
}

Producción:

false
    Explicación:

  • Una instancia de Nombre consta de un nombre y un apellido. Dos instancias de Name son iguales, según lo calculado por el método equals, si sus nombres son iguales y sus apellidos son iguales.
  • Los nombres y apellidos se comparan utilizando el método de igualdad definido en String. Dos strings son iguales si constan de los mismos caracteres en el mismo orden. Por lo tanto, dos instancias de Name son iguales si representan el mismo nombre. Por ejemplo, la siguiente invocación del método devuelve verdadero: new Name(“Shubham”, “Juneja”).equals(new Name(“Shubham”, “Juneja”)) El método principal del programa crea dos instancias de Name, ambas representan a Shubham junioja.
  • El programa coloca la primera instancia en un conjunto hash y luego verifica si el conjunto contiene el segundo. Las dos instancias de Nombre son iguales, por lo que podría parecer que el programa debería imprimir verdadero. Si lo ejecuta, es casi seguro que imprima falso.
  • ¿Por qué no la salida esperada?

    • El error es que Name viola el contrato hashCode. Esto puede parecer extraño, ya que Name ni siquiera tiene un método hashCode, pero ese es precisamente el problema. La clase Name anula el método equals y el contrato hashCode exige que los objetos equal tengan códigos hash iguales. Para cumplir con este contrato, debe anular hashCode siempre que anule equals.
    • Debido a que no puede anular hashCode, la clase Name hereda su implementación de hashCode de Object. Esta implementación devuelve un código hash basado en la identidad. En otras palabras, es probable que objetos distintos tengan valores hash desiguales, incluso si son iguales. Name no cumple con el contrato hashCode, por lo que no se especifica el comportamiento de un conjunto hash que contiene elementos Name.
    • Cuando el programa coloca la primera instancia de Nombre en el conjunto de hash, el conjunto coloca una entrada para esta instancia en un depósito de hash. El conjunto elige el depósito hash en función del valor hash de la instancia, calculado por su método hashCode. Cuando verifica si la segunda instancia de Nombre está contenida en el conjunto de hash, el programa elige qué depósito buscar en función del valor de hash de la segunda instancia. Debido a que la segunda instancia es distinta de la primera , es probable que tenga un valor hash diferente.

    Solución:

    • Si los dos valores hash se asignan a depósitos diferentes, el método contains devolverá false . Supongamos que las dos instancias de Name se asignan al mismo depósito. Todas las implementaciones de HashSet que conocemos tienen una optimización en la que cada entrada almacena el valor hash de su elemento además del propio elemento. Al buscar un elemento, la implementación selecciona el depósito hash apropiado y recorre sus entradas, comparando el valor hash almacenado en cada entrada con el valor hash del elemento deseado. Solo si los dos valores hash son iguales, la implementación verifica la igualdad de los elementos. Esta optimización tiene sentido porque suele ser mucho más económico comparar códigos hash que elementos.
    • Debido a esta optimización, no es suficiente que el conjunto de hash busque en el depósito correcto; las dos instancias de Name deben tener valores hash iguales para que el conjunto hash los reconozca como iguales. Las probabilidades de que el programa imprima verdadero son, por lo tanto, las probabilidades de que dos objetos creados consecutivamente tengan el mismo código hash de identidad.
    • Los resultados pueden variar según la implementación de Java que se utilice, pero es muy poco probable que vea que el programa se imprime como verdadero en cualquier JRE que conozcamos. Para solucionar el problema, simplemente agregue un método hashCode apropiado a la clase Name . Una vez que se agrega este método, el programa imprimirá verdadero como se esperaba:
      public int hashCode() {
      return 63 * first.hashCode() + last.hashCode();
      }
      
      • Este artículo es una contribución de Shubham Juneja . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

        Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por shubhamjuneja11 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *