¿Cómo funcionarán los .equals y .hashCode predeterminados para mis clases?

106

Di que tengo mi propia clase

public class MyObj { /* ... */ }

Tiene algunos atributos y métodos. NO implementa iguales, NO implementa hashCode.

Una vez que llamamos equals y hashCode, ¿cuáles son las implementaciones predeterminadas? ¿De la clase de objeto? ¿Y qué son? ¿Cómo funcionarán los iguales predeterminados? ¿Cómo funcionará el código hash predeterminado y qué devolverá? == solo comprobará si hacen referencia al mismo objeto, por lo que es fácil, pero ¿qué pasa con los métodos equals () y hashCode ()?

alexeypro
fuente

Respuestas:

94

Sí, la implementación predeterminada es de Object (en términos generales; si hereda de una clase que redefinió iguales y / o hashCode, usará esa implementación en su lugar).

De la documentación:

equals

El método equals para la clase Object implementa la relación de equivalencia más discriminatoria posible en los objetos; es decir, para cualquier valor de referencia no nulo xey, este método devuelve verdadero si y solo si xey se refieren al mismo objeto (x == y tiene el valor verdadero).

hashCode

Por mucho que sea razonablemente práctico, el método hashCode definido por la clase Object devuelve enteros distintos para objetos distintos. (Esto generalmente se implementa convirtiendo la dirección interna del objeto en un número entero, pero el lenguaje de programación JavaTM no requiere esta técnica de implementación).

Etienne de Martel
fuente
50

Desde Objecten una de las implementaciones de JVM:

public boolean equals(Object object) {
    return this == object;
}

public int hashCode() {
    return VMMemoryManager.getIdentityHashCode(this);
}

En ambos casos, solo se comparan las direcciones de memoria de los objetos en cuestión.

Brad Mace
fuente
7
¿De qué versión de JDK es? En v6u23 ea:public native int hashCode();
khachik
@kha - Tienes razón, creo que rastreé una de las implementaciones nativas para ver lo que realmente hizo
Brad Mace
10

Hay implementaciones predeterminadas de equals()y hashCode()en Object. Si no proporciona su propia implementación, se utilizarán. Porque equals()esto significa una ==comparación: los objetos solo serán iguales si son exactamente el mismo objeto. Porque hashCode()el Javadoc tiene una buena explicación.

Para obtener más información, consulte Effective Java, Chapter 3 (pdf), item 8.

Jorn
fuente
1

Sí, de la Objectclase, ya que su clase extiende Object implícitamente. equalssimplemente regresa this == obj. hashCodela implementación es nativa. Solo una conjetura: devuelve el puntero al objeto.

Khachik
fuente
2
Es un puntero al objeto ubicado en la memoria, pero no es una dirección de memoria del objeto. El GC puede mover el objeto en la memoria y el código hash seguirá siendo el mismo.
Jeremy
@Jeremy Gracias. stackoverflow.com/questions/2427631/… puede ser interesante.
Khachik
1

Si no proporciona su propia implementación, se utilizará una derivada de Object. Está bien, a menos que planee poner sus instancias de clase en, por ejemplo, HashSet (cualquier colección que realmente use hashCode ()), o algo que necesite verificar la igualdad del objeto (es decir, el método contains () de HashSet). De lo contrario, funcionará incorrectamente, si eso es lo que está pidiendo.

Es bastante fácil proporcionar su propia implementación de estos métodos gracias a HashCodeBuilder y EqualsBuilder de Apache Commons Lang .

Paweł Dyda
fuente
(a) ¿Por qué dice que la implementación predeterminada de la clase Object de 'equals' no funcionará correctamente con HashSet? Eso contradice las otras respuestas en esta página. (b) Gracias por los enlaces de Commons Lang.
Basil Bourque
1
@Basil: No creo que eso contradiga. Por supuesto, la implementación predeterminada funcionaría ... de alguna manera, pero no de la manera esperada. Es decir, dado que equals () usa la igualdad de referencia, dos objetos idénticos serían "diferentes" a los ojos de la implementación predeterminada. Como resultado, puede terminar teniendo dos instancias diferentes de exactamente lo mismo en su conjunto. Y el uso bastante típico de Conjuntos es cuando desea eliminar duplicados ...
Paweł Dyda
@ PawełDyda: El comportamiento predeterminado es generalmente correcto para tipos mutables. Si Fooy Barson referencias a dos instancias diferentes de un tipo mutable, y existe un método (por ejemplo SomeMutatingMethod) tal que Foo.SomeMutatingMethod()no afecta de Barla misma manera que lo hace Foo, esa diferencia debería ser suficiente para considerar los objetos como desiguales.
supercat
0

Developerworks de IBM dice:

Bajo esta implementación predeterminada, dos referencias son iguales solo si se refieren exactamente al mismo objeto. De manera similar, la implementación predeterminada de hashCode () proporcionada por Object se deriva asignando la dirección de memoria del objeto a un valor entero.

Sin embargo, para estar seguro de los detalles exactos de implementación para la versión de Java de un proveedor en particular, probablemente sea mejor buscar como fuente (si está disponible)

brabster
fuente