@Override hashCode()

Hola, buenos días, alguien podría explicarme el porqué de la necesidad de reescribir el metodo hascode() de los objetos si van hacer guardados en un hashset y si su modificación sigue algún patrón en especial y ademas también es necesario el cambio del método equals, se es que básico , pero no he encontrado información suficientemente clara en Internet.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

HashSet y HashMap

El hashCode() es importante para objetos que van a ser guardados en HashSet, o si van a ser usados como llaves en un HashMap, porque internamente esas colecciones usan el hashCode() de los objetos para mantenerlos ordenados.

El hashCode() no necesariamente debe ser único; si varios objetos tienen el mismo hashCode simplemente se agrupan juntos y el algoritmo de búsqueda al llegar a ese grupo, ya busca con el equals. Pero es mucho más rápido llegar primero por hashCode, porque es un vil entero y comparar enteros es de lo más rápido que puede hacer una computadora.

El equals() también es importante tenerlo porque se va a usar para cuando un HashSet o HashMap tenga dos objetos con el mismo hashCode. Si no lo sobreescribes, se usará la implementación de Object que compara si son realmente la misma instancia. Si eso te sirve, pues qué bien. Pero si tienes un caso en que tienes un objeto en un HashSet o como llave de un HashMap y te pasan otra instancia con los mismos valores para preguntar set.contains() o map.get(), entonces necesitas tener el equals() porque de otra forma podrían obtener una respuesta errónea (que el set o el map te digan que no contienen el objeto cuando realmente sí tienen uno igual).

Comportamiento por default y especialización

A ver si me sale una respuesta sencilla ( luego echo mucho choro )

Acá te va una descripción del comportamiento por default, como escribir equals y hashCode y porque es importante.

Lo que escribió Ezamudio es correcto y dicho en menos palabras. Si encuentras que la semana que viene tienes la misma pregunta quizá convenga que le dediques más tiempo que veas los ejemplos que siguen.

Comportamiento default

Estos métodos están definidos por la clase   que es de donde heredan todos correcto? Como la clase object no puede saber como vas a crear una subclase de ella define estos dos métodos más o menos así:

 

Es decir el   dice  , solo si es exactamente el mismo valor de referencia ejemplo:

 

Como  b "apuntan" al mismo objeto pues "==" regresa true. Lo siguiente sería false:

 

Es claro que aquí   y   apuntan a objetos diferentes no? Bueno hasta aquí todo claro espero respecto a equals ( rayos ya no me quedo corto el ejemplo )

Sobre hashCode ese   se puede pensar como un numero consecutivo que la JVM le asigna a un objeto, o se se prefiere ( y se tiene familiaridad con C ) se puede pensar que es la dirección de memoria del objeto. No es necesariamente ninguna de las dos, basta con pensar que dos objetos diferentes de la misma clase no van a tener el mismo número.

Especialización

Cuando se crea una subclase de Object ( básicamente siempre que se define una clase ) se tiene la opción de definir CUANDO un objeto es igual a otro.

Por ejemplo si ponemos una clase Moneda:

 

Podriamos definir cuando un peso es igual a otro así

 

No importa mucho porque el valor * 33 + codigo.hashCode(), el chiste es que para la misma moneda con el mismo valor siempre de el mismo hashcode.

Con toda esta definición se hace muchísimo más fácil crear dos objetos separados que representen la misma moneda:

 

Lo mismo con el hashCode:

 

Bueno hasta aquí queda claro como es el comportamiento por omisión y como es el comportamiento cuando se especializa la clase ( cuando se hereda pues) pero aún no está claro porque es importante.

Uso en colecciones

La mayoría si no es que todas las clases del paquete   basan su comportamiento en la definición de estos dos métodos , para funcionar correctamente, a veces en solo uno de ellos.

Por ejemplo el método   de   regresa true solo cuando la comparación usando equals regresa true:

 

Sin la sobreescritura de estos métodos siempre te regresaría false, porque   nunca regresaría true.

Lo mismo pasa con, por ejemplo el HashMap ( adios definitivamente mi ejemplo corto ) , el hashmap utiliza el hashCode para almacenar un objeto, y cuando lo vas a buscar no recorre toda la estructura, va directamente a donde sabe que lo dejo. Es como un diccionario, donde cuando buscas una palabra no ojeas todas las paginas, sino que te vas directamente a la letra.

 

Cuando se invoca el método "get", se calcula el hashCode de la moneda, en este caso la moneda que pasamos no es la misma con la que se guardo el dulce, es decir no es la misma instancia, aunque si representa el mismo valor. Como da el mismo hashCode entonces si nos regresa correctamente el dulce guardado ahí.

Si no se sobrescribieran estos métodos el ejemplo del la lista sería:

 

Es decir tendríamos que escribir la comparación nosotros mismos cada vez y una o dos veces no hace daño, pero cuando se tiene un programa grande estas comparaciones aparecen decenas o cientos de veces. El hashmap ni se podría usar, tendríamos que conservar la referencia a la llave con la que se guardo siempre con lo cual no nos serviría de nada.

Osease

Siempre ponlos, a menos claro que lo que desees es precisamente el comportamiento por omisión.

Espero que esto te ayude ( y a quien tuviera la misma pregunta ).

Imagen de gallark

Gracias a ambos, despues de

Gracias a ambos, despues de estas explicaciones, me ha quedado completamente claro el panorama. Saludos compañeros del foro.

Imagen de benek

¿Único?

 

A lo mejor te entendí mal, pero si no, tu texto sugiere que el hashCode() es único por objeto, lo cuál no es así. Puede que varios objetos generen el mismo hashCode(), es totalmente válido y legal.

Imagen de ezamudio

hasCode

benek, es que su método que debe ser único es hasCode, no hashCode. Es otra cosa :)

El hashCode puede estar repetido en varios objetos. Pero el contrato establece que dos objetos que se consideran iguales por equals(), sí deben tener el mismo hashCode().

Ah si. El valor debe de ser

Ah si.

El valor debe de ser único por objeto que represente lo mismo ( lo que Oscar quizó decir es: ) "idealmente".

Pero si es correcto, dos objetos incluso de la misma clase pueden tener el mismo hashCode y diferente equals. Lo que si es importante es que dos objetos que den true para equals deben de regresar el mismo hashCode, ahi si no hay vuelta de hoja.

Gracias por la aclaración.

Va un ejemplo ( este si lo compilé ) :

 

Salida: