java - que - Hashcode y Equals para Hashset
para que es el hashcode (6)
Esta pregunta ya tiene una respuesta aquí:
Por favor aclarar mi duda en Hashset. Considere el siguiente código,
class Person
{
String name;
Person(String n)
{
name=n;
}
public String getName()
{
return name;
}
@Override
public boolean equals(Object arg0) {
System.out.println("in equals");
Person obj=(Person)arg0;
System.out.println("1st "+getName());
System.out.println("2nd "+obj.getName());
if(this.getName().equals(obj.getName()))
{
return true;
}
return false;
}
@Override
public int hashCode() {
System.out.println("in hash code");
System.out.println(" value is "+Integer.valueOf(name.charAt(0)));
return Integer.valueOf(name.charAt(0));
}
}
en lo principal tengo el siguiente código
Person obj1=new Person("bcd");
Person obj2=new Person("cde");
Person obj3=new Person("abc");
Person obj4=new Person("abc");
Ahora si agrego estos objetos a hashset
Set<Person> sset=new HashSet<Person>();
sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj3);
Estoy recibiendo esta salida
in hash code
value is 98
in hash code
value is 97
in hash code
value is 99
in hash code
value is 97
in equals
1st abc
2nd abc
Pregunta 1 : ¿por qué la función equals () se llama solo una vez para verificar obj3 y obj4? ¿Por qué no se comprueba el resto de los objetos?
Pregunta 2 : Si la respuesta es porque ambos tienen el mismo código hash, solo se llamará a iguales, entonces ¿por qué no se solicita el siguiente código?
sset.add(obj1);
sset.add(obj4);
sset.add(obj2);
sset.add(obj4);
la salida es:
in hash code
value is 98
in hash code
value is 97
in hash code
value is 99
in hash code
value is 97
No va a entrar en el método equals () a pesar de que se agregan dos objetos al conjunto hash que tiene el mismo código hash.
Pregunta 3 : iteré el valor anterior e imprimí el contenido, pero ni el código de hash ni los iguales fueron llamados. ¿Cuándo es realmente útil anular el código de hash y el método de iguales?
Pregunta 4 : ¿Cuándo se hashCode()
y equals()
?
- No hay necesidad de llamar a
equals
sihashCode
difiere. - No hay necesidad de llamar a
hashCode
si(obj1 == obj2)
. - No hay necesidad de
hashCode
y / oequals
igual para iterar, no estás comparando objetos - Cuando sea necesario distinguir entre objetos.
Creo que todas sus preguntas serán respondidas si entiende cómo funcionan los Conjuntos, y en particular los HashSets. Un conjunto es una colección de objetos únicos, con Java que define la singularidad en el sentido de que no es igual a otra cosa (igual a devuelve falso).
El HashSet aprovecha los códigos hash para acelerar las cosas. Se supone que dos objetos que son iguales tendrán el mismo código hash. Sin embargo, no supone que dos objetos con el mismo código hash signifiquen que son iguales. Esta es la razón por la que cuando detecta un código hash en colisión, solo se compara con otros objetos (en su caso, uno) en el conjunto con el mismo código hash.
De acuerdo con el código fuente de jdk de javasourcecode.org, HashSet usa HashMap como su implementación interna, el código sobre el método de colocación de HashSet se encuentra a continuación:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
La regla es, en primer lugar, verificar el hash, luego verificar la referencia y luego poner el método de equivalencia de llamada del objeto.
Debería informarse sobre cómo asegurarse de que ha implementado equals y hashCode correctamente. Este es un buen punto de partida: ¿Qué problemas deben considerarse cuando se reemplaza a equals y hashCode en Java?
Debug HashSet con todos sus métodos y verá cómo funciona
Porque en el segundo caso, si agrega la misma referencia dos veces y HashSet
verifica esto en HashMap.put()
en el que se basa HashSet
:
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
Como puede ver, los equals
se llamarán solo si el hash de la clave que se agrega es igual a la clave ya presente en el conjunto y las referencias de estos dos son diferentes.