2011-03-31 11 views
6

aquí está mi código:HashSet contiene método, extraño comportamiento

public class testGui { 



    public static void main(String[] arg){ 
     class TESTS{ 
      String t; 

      public TESTS(String t){ 
       this.t = t; 
      } 

      @Override 
      public boolean equals(Object x){ 
       System.out.println("My method is called..."); 
       if(x instanceof TESTS){ 
        TESTS zzz = (TESTS) x; 
        return zzz.t.compareTo(t)==0; 
       } 
       else return false; 
      } 
     } 
     HashSet<TESTS> allItems = new HashSet<TESTS>(); 
     allItems.add(new TESTS("a")); 
     allItems.add(new TESTS("a")); 
     System.out.println(allItems.contains(new TESTS("a"))); 
    } 

} 

que no entiendo por qué el hashset contiene método no está llamando mi método es igual como lo mencionan en sus especificaciones:

Más formalmente , añade el elemento especificado, o, a este conjunto Si este conjunto contiene ningún elemento electrónico que tales (o == null e == null:? o.equals (e))

Mi código devuelve falso y no entra en mi método equals.

¡Muchas gracias por responder!

Respuesta

13

Cuando anula equals, también debe anular hashCode. De lo contrario, objetos iguales tendrán diferentes códigos hash y se considerarán desiguales.

También se recomienda encarecidamente no anular solohashCode. Pero esto no es esencial, ya que los objetos desiguales pueden tener el mismo código hash.

+2

No se considerarán desiguales. Es solo que el HashSet ni siquiera invocará el método equals porque solo lo hace para los hashCodes que conducen al mismo cubo. Y reemplazando solo hashCode no tiene ningún sentido, ya que HashSet siempre llamará a iguales para objetos que tengan los mismos hashCodes. –

+0

@JB, sí, el hecho de que conducen a diferentes cubos significa que se consideran 'desiguales' (considerados objetos diferentes). No me refiero al método 'iguales' cuando uso ese término. También acepto sobrescribir solo 'hashCode' es ilógico, por lo que recomiendo encarecidamente que no lo haga. Sin embargo, no rompe el contrato. –

+1

Sería bueno si la documentación de java menciona que hashcode se llama primero. Acabo de quemarme con este problema en java 5. – Aaron

3

También debe implementar hashCode, por lo que es coherente con equals. HashSet usa el método hashCode para decidir en qué depósito colocar un elemento y llama al equals solo cuando el código hash de dos elementos es el mismo.

Effective Java, 2ª Edición trata este de reglas (y las consecuencias de romperlo) en Tema 9: Siempre anular hashCode cuando se reemplaza equals.

+0

Muchas gracias chicos, fue realmente útil, encontré la respuesta antes de responder (no sabía cómo cancelar la pregunta), pero lo que escribiste es lo que hice y resolvió mi problema;). – Abbadon

7

El HashSet depende del HashCode de cada objeto. Antes de llamar al método equals, se llamará al método hashCode. Si los hashcodes son iguales, entonces el hashset lo considera digno de evaluar el método igual.

implementar un método código hash tal que si a.equals (b) == true, entonces a.hashCode() == b.hashCode()

y debe empezar a trabajar como era de esperar.

0

Como la mayoría de los comentarios han sido ... simplemente anula el método de código hash (muestra a continuación) y deberías estar bien.

+0

¿Qué ganas al multiplicar por 31? –

+0

este hilo ayudará a http://stackoverflow.com/questions/299304/why-does-javas-hashcode-in-string-use-31-as-a-multiplier – Prasanna