¿La mejor implementación? Esa es una pregunta difícil porque depende del patrón de uso.
A casi todos los casos, se propuso la aplicación razonable en buena Josh Bloch 's Effective Java en el punto 8 (segunda edición). Lo mejor es buscarlo allí porque el autor explica por qué el enfoque es bueno.
Una versión corta
Cree int resultay asigne un valor distinto de cero .
Para cada campof probado en el equals()método, calcule un código hash cde la siguiente manera:
Si el campo f es a boolean: calcular (f ? 0 : 1);
Si el campo de f es una byte, char, shorto int: Calcular (int)f;
Si el campo f es a long: calcular (int)(f ^ (f >>> 32));
Si el campo f es a float: calcular Float.floatToIntBits(f);
Si el campo f es a double: calcule Double.doubleToLongBits(f)y maneje el valor de retorno como cada valor largo;
Si el campo f es un objeto : utilice el resultado del hashCode()método o 0 si f == null;
Si el campo f es una matriz : vea cada campo como elemento separado y calcule el valor hash de forma recursiva y combine los valores como se describe a continuación.
Combine el valor hash ccon result:
result =37* result + c
Regreso result
Esto debería dar como resultado una distribución adecuada de los valores hash para la mayoría de las situaciones de uso.
Sí, tengo curiosidad por saber de dónde viene el número 37
Kip
17
Usé el ítem 8 del libro "Effective Java" de Josh Bloch.
dmeister el
39
@dma_k La razón para usar números primos y el método descrito en esta respuesta es asegurar que el código hash calculado sea único . Al usar números no primos, no puede garantizar esto. No importa qué número primo elijas, no hay nada mágico en el número 37 (lástima que 42 no sea un número primo, ¿eh?)
Simon Forsberg
34
@ SimonAndréForsberg Bueno, el código hash calculado no puede ser siempre único :) Es un código hash. Sin embargo, tuve la idea: el número primo tiene solo un multiplicador, mientras que el número primo tiene al menos dos. Eso crea una combinación adicional para que el operador de multiplicación produzca el mismo hash, es decir, cause colisión.
Si está satisfecho con la implementación efectiva de Java recomendada por dmeister, puede usar una llamada a la biblioteca en lugar de lanzar la suya propia:
Esto requiere Guava ( com.google.common.base.Objects.hashCode) o la biblioteca estándar en Java 7 ( java.util.Objects.hash) pero funciona de la misma manera.
A menos que uno tenga una buena razón para no usarlos, definitivamente debe usarlos en cualquier caso. (Formulándolo más fuerte, ya que debería ser formulado en mi humilde opinión.) Se aplican los argumentos típicos para usar implementaciones / bibliotecas estándar (mejores prácticas, bien probadas, menos propensas a errores, etc.).
Kissaki
77
@ justin.hughey pareces confundido. El único caso que debe anular hashCodees si tiene una costumbre equals, y para eso precisamente están diseñados estos métodos de biblioteca. La documentación es bastante clara sobre su comportamiento en relación con equals. Una implementación de biblioteca no pretende absolverlo de saber cuáles son las características de una hashCodeimplementación correcta : estas bibliotecas le facilitan la implementación de una implementación tan conforme para la mayoría de los casos en los que equalsse anula.
bacar
66
Para cualquier desarrollador de Android que busque la clase java.util.Objects, solo se introdujo en API 19, así que asegúrese de estar ejecutando en KitKat o superior, de lo contrario obtendrá NoClassDefFoundError.
Andrew Kelly
3
La mejor respuesta es IMO, aunque a modo de ejemplo preferiría haber elegido el java.util.Objects.hash(...)método JDK7 que el método de la guayaba com.google.common.base.Objects.hashCode(...). Creo que la mayoría de la gente elegiría la biblioteca estándar en lugar de una dependencia adicional.
Malte Skoruppa
2
Si hay dos argumentos o más y si alguno de ellos es una matriz, el resultado podría no ser el esperado porque hashCode()para una matriz es solo su java.lang.System.identityHashCode(...).
starikoff
59
Es mejor utilizar la funcionalidad proporcionada por Eclipse, que hace un trabajo bastante bueno y puede poner sus esfuerzos y energía en el desarrollo de la lógica empresarial.
+1 Una buena solución práctica. La solución de dmeister es más completa, pero tiendo a olvidar manejar los valores nulos cuando intento escribir códigos hash.
Quantum7
1
+1 De acuerdo con Quantum7, pero diría que también es realmente bueno entender qué está haciendo la implementación generada por Eclipse y de dónde obtiene sus detalles de implementación.
jwir3
15
Lo sentimos, pero las respuestas relacionadas con la "funcionalidad proporcionada por [algunos IDE]" no son realmente relevantes en el contexto del lenguaje de programación en general. Hay docenas de IDEs y esto no responde la pregunta ... principalmente porque se trata más de la determinación algorítmica y directamente asociada a la implementación de equals (), algo de lo que un IDE no sabrá nada.
@Overridepublicint hashCode(){// Start with a non-zero constant. Prime is preferredint result =17;// Include a hash for each field.// Primatives
result =31* result +(booleanField ?1:0);// 1 bit » 32-bit
result =31* result + byteField;// 8 bits » 32-bit
result =31* result + charField;// 16 bits » 32-bit
result =31* result + shortField;// 16 bits » 32-bit
result =31* result + intField;// 32 bits » 32-bit
result =31* result +(int)(longField ^(longField >>>32));// 64 bits » 32-bit
result =31* result +Float.floatToIntBits(floatField);// 32 bits » 32-bitlong doubleFieldBits =Double.doubleToLongBits(doubleField);// 64 bits (double) » 64-bit (long) » 32-bit (int)
result =31* result +(int)(doubleFieldBits ^(doubleFieldBits >>>32));// Objects
result =31* result +Arrays.hashCode(arrayField);// var bits » 32-bit
result =31* result + referenceField.hashCode();// var bits » 32-bit (non-nullable)
result =31* result +// var bits » 32-bit (nullable) (nullableReferenceField ==null?0: nullableReferenceField.hashCode());return result;}
EDITAR
Normalmente, cuando anula hashcode(...), también desea anular equals(...). Entonces, para aquellos que lo implementarán o ya lo implementaron equals, aquí hay una buena referencia de mi Github ...
@Overridepublicboolean equals(Object o){// Optimization (not required).if(this== o){returntrue;}// Return false if the other object has the wrong type, interface, or is null.if(!(o instanceofMyType)){returnfalse;}MyType lhs =(MyType) o;// lhs means "left hand side"// Primitive fieldsreturn booleanField == lhs.booleanField
&& byteField == lhs.byteField
&& charField == lhs.charField
&& shortField == lhs.shortField
&& intField == lhs.intField
&& longField == lhs.longField
&& floatField == lhs.floatField
&& doubleField == lhs.doubleField
// Arrays&&Arrays.equals(arrayField, lhs.arrayField)// Objects&& referenceField.equals(lhs.referenceField)&&(nullableReferenceField ==null? lhs.nullableReferenceField ==null: nullableReferenceField.equals(lhs.nullableReferenceField));}
si equals () devuelve verdadero para dos objetos, entonces hashCode () debería devolver el mismo valor. Si equals () devuelve falso, entonces hashCode () debería devolver valores diferentes
No puedo estar de acuerdo contigo. Si dos objetos tienen el mismo código hash, no tiene que significar que sean iguales.
Si A es igual a B, entonces A.hashcode debe ser igual a B.hascode
pero
si A.hashcode es igual a B.hascode no significa que A debe ser igual a B
Si (A != B) and (A.hashcode() == B.hashcode()), eso es lo que llamamos colisión de función hash. Es porque el codominio de la función hash siempre es finito, mientras que su dominio generalmente no lo es. Cuanto más grande es el codominio, con menos frecuencia debe ocurrir la colisión. Las buenas funciones de hash deberían devolver diferentes hashes para diferentes objetos con la mayor posibilidad posible dado el tamaño de codominio particular. Sin embargo, rara vez se puede garantizar por completo.
Krzysztof Jabłoński
Esto debería ser solo un comentario a la publicación anterior a Gray. Buena información pero en realidad no responde la pregunta
Christopher Rucinski
Buenos comentarios, pero tenga cuidado al usar el término 'objetos diferentes' ... porque equals () y, por lo tanto, la implementación de hashCode () no son necesariamente sobre objetos diferentes en un contexto OO, pero generalmente son más sobre sus representaciones de modelo de dominio (por ejemplo, dos las personas pueden ser consideradas iguales si comparten un código de país e ID de país, aunque estos pueden ser dos 'objetos' diferentes en una JVM, se les considera 'iguales' y tienen un código hash dado) ...
Darrell Teague
7
Si usa eclipse, puede generar equals()y hashCode()usar:
Fuente -> Generar hashCode () y equals ().
Con esta función, puede decidir qué campos desea utilizar para la igualdad y el cálculo del código hash, y Eclipse genera los métodos correspondientes.
La desventaja de esta API es que paga el costo de la construcción de objetos cada vez que llama a equals y hashcode (a menos que su objeto sea inmutable y precalcule el hash), lo que puede ser mucho en ciertos casos.
James McMahon
Este era mi enfoque favorito, hasta hace poco. Me he encontrado con StackOverFlowError mientras usaba un criterio para la asociación SharedKey OneToOne. ObjectsAdemás , la clase proporciona métodos hash(Object ..args)y equals()desde Java7 en adelante. Se recomiendan para cualquier aplicación que use jdk 1.7+
Diablo
@Diablo, supongo, su problema fue un ciclo en el gráfico de objetos y luego no tiene suerte con la mayoría de las implementaciones, ya que debe ignorar alguna referencia o romper el ciclo (mandando un IdentityHashMap). FWIW Uso un código hash basado en id e igual para todas las entidades.
maaartinus
6
Solo una nota rápida para completar otra respuesta más detallada (en términos de código):
Si entiendo su pregunta correctamente, tiene una clase de colección personalizada (es decir, una nueva clase que se extiende desde la interfaz de la Colección) y desea implementar el método hashCode ().
Si su clase de colección extiende AbstractList, entonces no tiene que preocuparse por eso, ya existe una implementación de equals () y hashCode () que funciona iterando a través de todos los objetos y agregando sus hashCodes () juntos.
Ahora, si lo que desea es la mejor manera de calcular el código hash para una clase específica, normalmente uso el operador ^ (exclusivo a nivel de bit o) para procesar todos los campos que uso en el método igual:
(¿puedes obtener hashCode directamente desde int en Java en estos días? Creo que hace algo de autocasting ... si ese es el caso, omite toString, es feo).
el error está en la respuesta larga de about8.blogspot.com: obtener el código hash de una concatenación de cadenas te deja con una función hash que es la misma para cualquier combinación de cadenas que se sumen a la misma cadena.
SquareCog
1
Entonces, ¿esto es meta-discusión y no está relacionado con la pregunta? ;-)
Huppie
1
Es una corrección a una respuesta propuesta que tiene un defecto bastante significativo.
SquareCog
Esta es una implementación muy limitada
Christopher Rucinski
Su implementación evita el problema e introduce otro; Intercambio fooy barlleva a lo mismo hashCode. Su toStringAFAIK no se compila, y si lo hace, entonces es terriblemente ineficiente. Algo así 109 * getFoo().hashCode() + 57 * getBar().hashCode()es más rápido, más simple y no produce colisiones innecesarias.
maaartinus
2
Como solicitó específicamente colecciones, me gustaría agregar un aspecto que las otras respuestas aún no han mencionado: un HashMap no espera que sus claves cambien su código hash una vez que se agregan a la colección. Derrotaría todo el propósito ...
Prefiero usar métodos de utilidad de la biblioteca de Google Collections de la clase Objects que me ayuda a mantener mi código limpio. Muy a menudo equalsy los hashcodemétodos se realizan a partir de la plantilla de IDE, por lo que no están limpios para leer.
Aquí hay otra demostración del enfoque JDK 1.7+ con lógicas de superclase. Lo veo bastante convincente con la clase de objeto hashCode () contada, dependencia pura de JDK y sin trabajo manual adicional. Tenga en cuenta que Objects.hash()es nulo tolerante.
No he incluido ninguna equals()implementación, pero en realidad la necesitarás.
import java.util.Objects;publicclassDemo{publicstaticclass A {privatefinalString param1;public A(finalString param1){this.param1 = param1;}@Overridepublicint hashCode(){returnObjects.hash(super.hashCode(),this.param1);}}publicstaticclass B extends A {privatefinalString param2;privatefinalString param3;public B(finalString param1,finalString param2,finalString param3){super(param1);this.param2 = param2;this.param3 = param3;}@Overridepublicfinalint hashCode(){returnObjects.hash(super.hashCode(),this.param2,this.param3);}}publicstaticvoid main(String[] args){
A a =new A("A");
B b =new B("A","B","C");System.out.println("A: "+ a.hashCode());System.out.println("B: "+ b.hashCode());}}
tienen lo mismo hashCode, es decir, 31*(a+b) + ccomo el multiplicador utilizado para List.hashCodese reutiliza aquí. Obviamente, las colisiones son inevitables, pero producir colisiones innecesarias es simplemente ... innecesario.
No hay nada sustancialmente inteligente sobre el uso 31. El multiplicador debe ser impar para evitar perder información (cualquier multiplicador par pierde al menos el bit más significativo, los múltiplos de cuatro pierden dos, etc.). Cualquier multiplicador impar es utilizable. Los pequeños multiplicadores pueden conducir a un cálculo más rápido (el JIT puede usar cambios y adiciones), pero dado que la multiplicación tiene una latencia de solo tres ciclos en Intel / AMD moderno, esto apenas importa. Los multiplicadores pequeños también conducen a una mayor colisión para entradas pequeñas, lo que a veces puede ser un problema.
Usar un primo no tiene sentido ya que los primos no tienen significado en el anillo Z / (2 ** 32).
Por lo tanto, recomendaría usar un número impar grande elegido al azar (siéntase libre de tomar un primo). Como las CPU i86 / amd64 pueden usar una instrucción más corta para los operandos que se ajustan en un solo byte firmado, existe una pequeña ventaja de velocidad para multiplicadores como 109. Para minimizar las colisiones, tome algo como 0x58a54cf5.
Usar diferentes multiplicadores en diferentes lugares es útil, pero probablemente no sea suficiente para justificar el trabajo adicional.
Al combinar valores hash, generalmente uso el método de combinación que se usa en la biblioteca boost c ++, a saber:
seed ^= hasher(v)+0x9e3779b9+(seed<<6)+(seed>>2);
Esto hace un trabajo bastante bueno para garantizar una distribución uniforme. Para una discusión sobre cómo funciona esta fórmula, vea la publicación de StackOverflow: Número mágico en boost :: hash_combine
Para una clase simple, a menudo es más fácil implementar hashCode () en función de los campos de clase que son verificados por la implementación equals ().
Lo más importante es mantener hashCode () y equals () consistentes: si equals () devuelve verdadero para dos objetos, entonces hashCode () debería devolver el mismo valor. Si equals () devuelve falso, entonces hashCode () debería devolver valores diferentes.
Como SquareCog ya lo ha notado. Si se genera código hash vez de concatenación de dos cadenas es extremadamente fácil de generar masas de colisiones: ("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc"). Es un defecto grave. Sería mejor evaluar el código hash para ambos campos y luego calcular la combinación lineal de ellos (preferiblemente usando primos como coeficientes).
Objects.hashCode(collection)
debería ser una solución perfecta!collection.hashCode()
( hg.openjdk.java.net/jdk7/jdk7/jdk/file/9b8c96f96a0f/src/share/… )Respuestas:
¿La mejor implementación? Esa es una pregunta difícil porque depende del patrón de uso.
A casi todos los casos, se propuso la aplicación razonable en buena Josh Bloch 's Effective Java en el punto 8 (segunda edición). Lo mejor es buscarlo allí porque el autor explica por qué el enfoque es bueno.
Una versión corta
Cree
int result
ay asigne un valor distinto de cero .Para cada campo
f
probado en elequals()
método, calcule un código hashc
de la siguiente manera:boolean
: calcular(f ? 0 : 1)
;byte
,char
,short
oint
: Calcular(int)f
;long
: calcular(int)(f ^ (f >>> 32))
;float
: calcularFloat.floatToIntBits(f)
;double
: calculeDouble.doubleToLongBits(f)
y maneje el valor de retorno como cada valor largo;hashCode()
método o 0 sif == null
;Combine el valor hash
c
conresult
:Regreso
result
Esto debería dar como resultado una distribución adecuada de los valores hash para la mayoría de las situaciones de uso.
fuente
Si está satisfecho con la implementación efectiva de Java recomendada por dmeister, puede usar una llamada a la biblioteca en lugar de lanzar la suya propia:
Esto requiere Guava (
com.google.common.base.Objects.hashCode
) o la biblioteca estándar en Java 7 (java.util.Objects.hash
) pero funciona de la misma manera.fuente
hashCode
es si tiene una costumbreequals
, y para eso precisamente están diseñados estos métodos de biblioteca. La documentación es bastante clara sobre su comportamiento en relación conequals
. Una implementación de biblioteca no pretende absolverlo de saber cuáles son las características de unahashCode
implementación correcta : estas bibliotecas le facilitan la implementación de una implementación tan conforme para la mayoría de los casos en los queequals
se anula.java.util.Objects.hash(...)
método JDK7 que el método de la guayabacom.google.common.base.Objects.hashCode(...)
. Creo que la mayoría de la gente elegiría la biblioteca estándar en lugar de una dependencia adicional.hashCode()
para una matriz es solo sujava.lang.System.identityHashCode(...)
.Es mejor utilizar la funcionalidad proporcionada por Eclipse, que hace un trabajo bastante bueno y puede poner sus esfuerzos y energía en el desarrollo de la lógica empresarial.
fuente
Aunque esto está vinculado a la
Android
documentación (Wayback Machine) y a Mi propio código en Github , funcionará para Java en general. Mi respuesta es una extensión de la respuesta de dmeister con un código que es mucho más fácil de leer y comprender.EDITAR
Normalmente, cuando anula
hashcode(...)
, también desea anularequals(...)
. Entonces, para aquellos que lo implementarán o ya lo implementaronequals
, aquí hay una buena referencia de mi Github ...fuente
Primero asegúrese de que igual se implementa correctamente. De un artículo de IBM DeveloperWorks :
Luego, asegúrese de que su relación con hashCode respete el contacto (del mismo artículo):
Finalmente, una buena función hash debería esforzarse por acercarse a la función hash ideal .
fuente
about8.blogspot.com, dijiste
No puedo estar de acuerdo contigo. Si dos objetos tienen el mismo código hash, no tiene que significar que sean iguales.
Si A es igual a B, entonces A.hashcode debe ser igual a B.hascode
pero
si A.hashcode es igual a B.hascode no significa que A debe ser igual a B
fuente
(A != B) and (A.hashcode() == B.hashcode())
, eso es lo que llamamos colisión de función hash. Es porque el codominio de la función hash siempre es finito, mientras que su dominio generalmente no lo es. Cuanto más grande es el codominio, con menos frecuencia debe ocurrir la colisión. Las buenas funciones de hash deberían devolver diferentes hashes para diferentes objetos con la mayor posibilidad posible dado el tamaño de codominio particular. Sin embargo, rara vez se puede garantizar por completo.Si usa eclipse, puede generar
equals()
yhashCode()
usar:Con esta función, puede decidir qué campos desea utilizar para la igualdad y el cálculo del código hash, y Eclipse genera los métodos correspondientes.
fuente
Hay una aplicación bien de la Effective Java 's
hashcode()
yequals()
la lógica en Apache Commons Lang . Checkout HashCodeBuilder y EqualsBuilder .fuente
Objects
Además , la clase proporciona métodoshash(Object ..args)
yequals()
desde Java7 en adelante. Se recomiendan para cualquier aplicación que use jdk 1.7+IdentityHashMap
). FWIW Uso un código hash basado en id e igual para todas las entidades.Solo una nota rápida para completar otra respuesta más detallada (en términos de código):
Si considero la pregunta cómo-do-i-create-a-hash-table-in-java y especialmente la entrada de preguntas frecuentes de jGuru , creo que algunos otros criterios sobre los cuales se podría juzgar un código hash son:
fuente
Si entiendo su pregunta correctamente, tiene una clase de colección personalizada (es decir, una nueva clase que se extiende desde la interfaz de la Colección) y desea implementar el método hashCode ().
Si su clase de colección extiende AbstractList, entonces no tiene que preocuparse por eso, ya existe una implementación de equals () y hashCode () que funciona iterando a través de todos los objetos y agregando sus hashCodes () juntos.
Ahora, si lo que desea es la mejor manera de calcular el código hash para una clase específica, normalmente uso el operador ^ (exclusivo a nivel de bit o) para procesar todos los campos que uso en el método igual:
fuente
@ about8: hay un error bastante grave allí.
mismo código hash
probablemente quieras algo como
(¿puedes obtener hashCode directamente desde int en Java en estos días? Creo que hace algo de autocasting ... si ese es el caso, omite toString, es feo).
fuente
foo
ybar
lleva a lo mismohashCode
. SutoString
AFAIK no se compila, y si lo hace, entonces es terriblemente ineficiente. Algo así109 * getFoo().hashCode() + 57 * getBar().hashCode()
es más rápido, más simple y no produce colisiones innecesarias.Como solicitó específicamente colecciones, me gustaría agregar un aspecto que las otras respuestas aún no han mencionado: un HashMap no espera que sus claves cambien su código hash una vez que se agregan a la colección. Derrotaría todo el propósito ...
fuente
Utilizar los métodos de reflexión sobre Apache Commons EqualsBuilder y HashCodeBuilder .
fuente
Utilizo un pequeño contenedor
Arrays.deepHashCode(...)
porque maneja las matrices suministradas como parámetros correctamentefuente
cualquier método de hash que distribuya uniformemente el valor de hash en el rango posible es una buena implementación. Ver java efectivo ( http://books.google.com.au/books?id=ZZOiqZQIbRMC&dq=effective+java&pg=PP1&ots=UZMZ2siN25&sig=kR0n73DHJOn-D77qGj0wOxAxiZw&hl=en&sa=X&oi=res_resultante = a1& ulti =1 allí para la implementación de hashcode (elemento 9, creo ...).
fuente
Prefiero usar métodos de utilidad de la biblioteca de Google Collections de la clase Objects que me ayuda a mantener mi código limpio. Muy a menudo
equals
y loshashcode
métodos se realizan a partir de la plantilla de IDE, por lo que no están limpios para leer.fuente
Aquí hay otra demostración del enfoque JDK 1.7+ con lógicas de superclase. Lo veo bastante convincente con la clase de objeto hashCode () contada, dependencia pura de JDK y sin trabajo manual adicional. Tenga en cuenta que
Objects.hash()
es nulo tolerante.No he incluido ninguna
equals()
implementación, pero en realidad la necesitarás.fuente
La implementación estándar es débil y su uso conduce a colisiones innecesarias. Imagina un
Ahora,
y
tienen lo mismo
hashCode
, es decir,31*(a+b) + c
como el multiplicador utilizado paraList.hashCode
se reutiliza aquí. Obviamente, las colisiones son inevitables, pero producir colisiones innecesarias es simplemente ... innecesario.No hay nada sustancialmente inteligente sobre el uso
31
. El multiplicador debe ser impar para evitar perder información (cualquier multiplicador par pierde al menos el bit más significativo, los múltiplos de cuatro pierden dos, etc.). Cualquier multiplicador impar es utilizable. Los pequeños multiplicadores pueden conducir a un cálculo más rápido (el JIT puede usar cambios y adiciones), pero dado que la multiplicación tiene una latencia de solo tres ciclos en Intel / AMD moderno, esto apenas importa. Los multiplicadores pequeños también conducen a una mayor colisión para entradas pequeñas, lo que a veces puede ser un problema.Usar un primo no tiene sentido ya que los primos no tienen significado en el anillo Z / (2 ** 32).
Por lo tanto, recomendaría usar un número impar grande elegido al azar (siéntase libre de tomar un primo). Como las CPU i86 / amd64 pueden usar una instrucción más corta para los operandos que se ajustan en un solo byte firmado, existe una pequeña ventaja de velocidad para multiplicadores como 109. Para minimizar las colisiones, tome algo como 0x58a54cf5.
Usar diferentes multiplicadores en diferentes lugares es útil, pero probablemente no sea suficiente para justificar el trabajo adicional.
fuente
Al combinar valores hash, generalmente uso el método de combinación que se usa en la biblioteca boost c ++, a saber:
Esto hace un trabajo bastante bueno para garantizar una distribución uniforme. Para una discusión sobre cómo funciona esta fórmula, vea la publicación de StackOverflow: Número mágico en boost :: hash_combine
Hay una buena discusión sobre las diferentes funciones hash en: http://burtleburtle.net/bob/hash/doobs.html
fuente
Para una clase simple, a menudo es más fácil implementar hashCode () en función de los campos de clase que son verificados por la implementación equals ().
Lo más importante es mantener hashCode () y equals () consistentes: si equals () devuelve verdadero para dos objetos, entonces hashCode () debería devolver el mismo valor. Si equals () devuelve falso, entonces hashCode () debería devolver valores diferentes.
fuente
("abc"+""=="ab"+"c"=="a"+"bc"==""+"abc")
. Es un defecto grave. Sería mejor evaluar el código hash para ambos campos y luego calcular la combinación lineal de ellos (preferiblemente usando primos como coeficientes).foo
ybar
produce una colisión innecesaria, también.