2011-03-22 23 views
41

Por favor, aclare mi duda en Hashset. Considere el siguiente código,Hashcode e igual para Hashset

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 el 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 añado estos objetos para 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 igual() se llama solo una vez para verificar obj3 y obj4? ¿Por qué no se verifica para el resto de los objetos?

Pregunta 2: Si la respuesta es porque ambos tienen el mismo código hash, sólo entonces es igual será llamado, entonces ¿por qué no es llamado a continuación Código

sset.add(obj1); 
sset.add(obj4); 
sset.add(obj2); 
sset.add(obj4); 

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 dentro del método equals() aunque se hayan agregado dos mismos objetos al conjunto de hash que tiene el mismo código hash.

Pregunta 3: He repetido el valor anterior e imprimí el contenido pero no se han llamado ni hashcode ni iguales. cuando es realmente útil para anular el código hash y el método igual?

Pregunta 4: ¿Cuándo se llamará hashCode() y equals()?

+3

Mmh ... ¿leo esta pregunta sin formato de código? ... ¿Me formato él mismo para entenderlo? ... no, es tarde , Me voy a casa. N8. – Daniel

+0

@ Paŭlo Ebermann: No modifique el significado de una respuesta cuando edite; se redactó usando "código hash" y no "igual" en 2. intencionalmente. Eres libre de escribir una nueva respuesta si no estás de acuerdo con la mía. – Erik

+0

@Erik: Lo siento, ya que la pregunta era sobre llamar '.equals', pensé que la respuesta debería ser sobre esto también. (Sí, tienes razón, debería haber agregado un comentario). –

Respuesta

46
  1. No es necesario llamar al equals si hashCode es diferente.
  2. No hay necesidad de llamar al hashCode si (obj1 == obj2).
  3. No hay necesidad de hashCode y/o equals sólo para repetir - no se está comparando objetos
  4. Cuando sea necesario distinguir entre objetos.
+2

'HashMap' en realidad calcula el hash para encontrar el cubo correcto y lo usa antes de comparar la identidad del objeto con' == 'o llamar a' equals() ', pero de lo contrario, esto es correcto. 'equals()' no se llama en el segundo ejemplo porque '==' ya detectó el duplicado. –

+4

No hay necesidad de hashCode y/o simplemente iterar - no está comparando objetos --- Entonces, ¿cómo obtendría el depósito actual si no llama a hashcode en la iteración? –

16

Creo que todas sus preguntas serán contestadas si comprende cómo funcionan los Sets, y en particular los HashSets. Un conjunto es una colección de objetos únicos, con la singularidad de definición de Java en el sentido de que no es igual a nada (es decir, devuelve falso).

El HashSet aprovecha los hashcodes para acelerar las cosas. Supone que dos objetos que se igualan tendrán el mismo código hash. Sin embargo, no supone que dos objetos con el mismo código hash significan que son iguales. Es por eso que cuando detecta un código hash colisionante, solo se compara con otros objetos (en su caso uno) en el conjunto con el mismo código hash.

-3

favor depurar HashSet con todos sus métodos y verá cómo funciona

2

Debido a que en segundo caso de que la adición de una misma referencia dos veces y HashSet han cotejar con esto en HashMap.put() en el que HashSet se basa:

 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, se llamará a equals solo si el hash de la clave que se agrega es igual a la clave que ya está presente en el conjunto y las referencias de estos dos son diferentes.

11

según el código fuente del JDK de javasourcecode.org, HashSet utilizar HashMap como su aplicación en el interior, el código sobre el método put de HashSet es el siguiente:

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 comprobar el hash, a continuación, active la referencia y luego llamar al método de igualdad del objeto será puesto en.

Cuestiones relacionadas