2011-11-13 23 views
15

¿Cuál es el razonamiento detrás de la decisión de incluir estos métodos en java.lang.Object? Igualdad y hash no tiene sentido para muchas clases.¿Por qué equals y hashCode se definieron en Object?

Sería más lógico para hacer dos interfaces:

interface Equalable { 
    boolean equals(Equalable other); 
} 

interface Hashable extends Equalable { 
    int hashCode(); 
} 

Por ejemplo definición HashSet podría parecerse a

class HashSet<T extends Hashable> ... 

Sería evitar que uno de los errores de principiante común - el uso conjunto de elementos sin implementando equals/hashCode.

+0

Eche un vistazo [aquí] (http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx) para obtener un buen artículo sobre algo relacionado (por Jon Skeet). –

+1

el enlace parece muerto. [Este] (http://codeblog.jonskeet.uk/2008/12/05/redesigning-system-object-java-lang-object/) puede ser el mismo artículo. – tkokasih

Respuesta

13

Cuando implementamos un Interface tenemos inject (or accept) el contrato definido por la interfaz.

Equalable & Hashable son dos contratos diferentes. Pero si echamos un vistazo de cerca, entonces veremos que ambos dependen el uno del otro, lo que significa que son parte de un single interface, algo así como EqualableAndHashable.

Ahora la pregunta obvia es si deberían formar parte de esta nueva interfaz EqualableAndHashable o Object?

Vamos a descubrirlo. Tenemos == (equal operator) para verificar la igualdad de dos objetos. El operador == confirma si los valores/referencias son iguales para dos primitivas/objetos diferentes. Pero no siempre es posible responder simplemente consultando con el operador ==.

Ahora pregunta si esta igualdad, which is also a contract, se debe inyectar a través de interfaces o parte de la clase Object?

Si echamos un vistazo, no podemos simplemente decir algo como:

TypeX no garantiza la igualdad de contrato.

Se convertirá en un caos si algunos tipos de objetos ofrecen igualdad y otros no. Lo que significa que el objeto de TypeX debe respetar el contrato de igualdad, que también es cierto para todos los demás tipos de objetos. Por lo tanto, no debe inyectar igualdad desde una interfaz, porque la igualdad debe ser la parte del contrato para cualquier objeto por defecto, de lo contrario creará caos.

Así que necesitamos objetos para llegar a la implementación de equals. Pero no puede implementar solo el método equals, también necesita implementar el método hashcode.

+2

'=' es en realidad el operador de asignación;) –

+0

@DaveNewton gracias. cambiado en consecuencia – Kowser

+1

No entiendo el "caos" que mencionas. Implemento todo el tiempo estos métodos para usar mis clases en Conjuntos y Mapas. Sería más simple para mí evitar la implementación predeterminada a toda costa, así que estoy por eliminar estos métodos de Object. :RE –

1

(Personalmente, si estuvieran en una interfaz, que había puesto a ambos en allí para evitar al menos una clase de equals/hashCode errores.)

Creo que querría una implementación de objeto, como un mecanismo de repliegue, lo que significa que todo tendría una implementación de todos modos, interfaz o no.

Sospecho que mucho de esto es histórico; La programación de Java hoy se ve bastante diferente a la programación de Java en aquel entonces.

0

Es una implementación genérica. Se supone que debes anular la implementación si la necesitas. De lo contrario, tiene una implementación predeterminada razonable.

Al menos los iguales deben tener. Crear interfaces para operaciones básicas probablemente involucraría mucha sobrecarga.

+0

Tu punto es? – delnan

1

Mhh no estoy seguro, pero cuando se lanzó Java 1.0 los genéricos aún no existían. Se agregaron en Java 5.0 en 2004 ... por lo que su propuesta no se pudo implementar para Java 1.0

+2

Si 'TreeSet' podría requerir claves para implementar' Comparable' si no se especificó 'Comparator', ¿por qué no pudo HashSet requerir' Hashable'? Hay más que genéricos. – meriton

0

Si tiene una lista de objetos y llama al método contains, ¿qué debería hacer Java? Creo que la implementación predeterminada (comparar referencias) es una decisión decente. De esta forma, no tendrá que implementarse equals y hashcode para cada clase que use en una colección.

1

Originalmente, en Java, no había genéricos. Esto fue solucionado permitiendo que cualquier Object sea miembro de cualquier colección, y por lo tanto cualquier Object necesitó hashCode y equals. Por ahora está demasiado atrincherado para cambiar.

+0

La ausencia de genéricos es irrelevante. Por ejemplo, no impidió que 'TreeSet' requiriera claves para implementar' Comparable' si no se especificaba 'Comparador'. – meriton

2

La implementación predeterminada en java.lang.Object tiene sentido. Muchas veces, es lo suficientemente bueno. En las aplicaciones web/JPA, me encuentro muy rara vez, si es que alguna vez anulo, equals y hashCode.

Una pregunta mejor podría ser: para objetos de valor inmutables como String, Long etc., ¿por qué no se puede anular el operador == para llamar a iguales(), como se puede hacer en C#? He visto muchos más errores debido a que tengo el valor predeterminado/hashCode que no está haciendo lo correcto. Por ejemplo,

Long x = obj.getId(); 
Long y = obj2.getId(); 
if (x == y) { // oops, probably meant x.equals(y)! } 

Es una buena pregunta, sin embargo, ¿por qué los métodos predeterminados no están encerrados detrás de una interfaz de marcado como el Object.clone predeterminado(). Existe una implementación predeterminada, pero debe reconocer explícitamente que desea usarla implementando Cloneable. Fácilmente podría haber sido una interfaz de etiquetado similar como Collectible o Equatable, y luego la firma para los métodos de cobros podría haber sido Equatable en lugar de Object.

0

Realmente, es solo por conveniencia, y es mejor así. Bueno, piensa en lo que se necesitaría para hacer igualdad de objetos si no se tiene el método .equals:

AreEqual(Object obj1,Object obj2) { 
    if(!obj1 instanceof Equalable) return false; 
    if(!obj2 instanceof Equalable) return false; 
    return ((Equalable)(obj1).equals((Equalable)obj2); 
} 

Esto es cierto incluso para un código hash. A veces la igualdad de referencia es suficiente. Si has hecho que HashSet solo acepte objetos que implementen Hashable, entonces tendrías que convertir explícitamente tus clases Hashable, aunque solo quieras la igualdad de referencia. Y ha reducido la universalidad de una estructura de datos por lo demás excelente.

Es mejor que Object tenga una función predeterminada (y algunas veces suficiente) .equals y .hashCode y cause algunos problemas a los recién llegados, que hacer que los usuarios frecuentes del lenguaje se desplacen a través de más burocracia.

0

Cualquier objeto, independientemente de su tipo, puede responder con sensatez si es equivalente a cualquier otro objeto, incluso si el tipo del otro objeto es uno que nunca se haya escuchado. Si nunca se ha escuchado sobre el tipo del otro objeto, ese solo hecho es suficiente para informar que no es equivalente al último objeto.

Cuestiones relacionadas