fbpx

equals() y hashCode() en JAVA

HashCode es un identificador de 32 bits que se almacena en un Hash en la instancia de la clase. Toda clase debe proveer de un método hashCode() que permite recuperar el Hash Code asignado, por defecto, por la clase Object. El HashCode tiene una especial importancia para el rendimiento de las tablas hash y otras estructuras de datos que agrupan objetos en base al cálculo de los HashCode.

Normalmente se sobrescribe el método para que se comporte de forma acorde a la que lo hace .equals(), es decir, si el método .equals() dice que si dos objetos son iguales, estos han de tener el mismo valor hash.

El método hashCode()

En Java, el valor del código hash de un objeto se devuelve llamando al método hashCode() en ese objeto. Este método se implementa, de manera predeterminada, en la clase Object y, por lo tanto, también lo heredan las clases definidas por el usuario.

hashCode() devuelve el mismo valor entero (cuando se invoca en el mismo objeto durante la misma instancia de una aplicación Java), siempre que no se modifique ningún dato utilizado por el método equals().

El contrato general del método hashCode() es:

  • hashCode() debe devolver el mismo valor entero, a menos que se modifique el método equals().
  • El valor de un código hash de objeto puede cambiar en múltiples ejecuciones de la misma aplicación.
  • Si dos objetos son iguales según el método equals(), entonces su código hash debe ser el mismo.
  • Si dos objetos no son iguales según el método equals(), su valor de código hash puede o no ser igual.
class Main {
    public static void main(String[] args){
        UsuarioDto a = new UsuarioDto("Juan", "juan@email.com");
        String b = new UsuarioDto("Maria", "maria@email.com");

        if(a.equals(b)){
            System.out.println("Los hash deben ser iguales:");
            System.out.println(a.hashCode());
            System.out.println(b.hashCode());
        }

        String c = "mundo";
        String d = "world";

        if(!c.equals(d)){
            System.out.println("Probablemente no son iguales, aunque pueden ser iguales:");
            System.out.println(c.hashCode());
            System.out.println(d.hashCode());
        }
    }
}

Implementaciones de hashCode()

Cuanto mejor sea el algoritmo hash que usamos para calcular los códigos hash, mejor será el rendimiento de las tablas hash.

Echemos un vistazo a una implementación “estándar” que usa dos números primos para agregar aún más singularidad a los códigos hash calculados:

@Override
public int hashCode() {
    int hash = 7;
    hash = 31 * hash + (int) id;
    hash = 31 * hash + (nombre == null ? 0 : nombre.hashCode());
    hash = 31 * hash + (email == null ? 0 : email.hashCode());
    return hash;
}

Desde Java 7, tenemos un método en la clase Objects que podemos usar en nuestra implementación de hashCode(), el método required pasar por parámetro las propiedades de la clase que lo utiliza, el método en cuestión es Objects.hash():

Objects.hash(nombre, email)

El uso de IDES para implementar los el método hashCode() es bastante popular y su uso es recomendado.

IntelliJ IDEA genera la siguiente implementación:

    @Override
    public int hashCode() {
        int result = nombre != null ? nombre.hashCode() : 0;
        result = 31 * result + (email != null ? email.hashCode() : 0);
        return result;
    }

El método equals()

De acuerdo con la documentación de java del método equals(), cualquier implementación debe cumplir con los siguientes principios:

  • Para cualquier objeto x, x.equals(x) debería devolver true.
  • Para dos objetos x e y, x.equals(y) debería devolver true si y solo si y.equals(x) devuelve true.
  • Para varios objetos x, y y z, si x.equals(y) devuelve verdadero e y.equals(z) devuelve verdadero, entonces x.equals(z) debería devolver verdadero.
  • Varias invocaciones de x.equals(y) deberían arrojar el mismo resultado, a menos que se modifique alguna de las propiedades del objeto que se usa en la implementación del método equals().
  • La implementación del método equals() devuelve true solo cuando ambas referencias apuntan al mismo objeto.

Los comentarios están cerrados.