2011-08-11 11 views
10

Novato pregunta sobre HashSet javaentendimiento contiene método de Java HashSet

Set<User> s = new HashSet<User>(); 
User u = new User(); 
u.setName("name1"); 
s.add(u); 
u.setName("name3"); 
System.out.println(s.contains(u)); 

¿Puede alguien explicar por qué esta salida de código falsa? Además, este código ni siquiera iguala el método de usuario. Pero de acuerdo con las fuentes de HashSet y HashMap tiene que llamarlo. El método es igual a User simplemente llama igual en el nombre del usuario. Método hashCode retorno hashCode del nombre de usuario

+0

Quizás quiso implementar User.equals método '()' ? –

+0

Para citar a Jon Skeet: "Los objetos en hashsets deben ser inmutables o se debe ejercer disciplina para no cambiarlos después de que se hayan utilizado en un hashset (o hashmap)". - http://stackoverflow.com/questions/4718009/mutable-objects-and-hashcode – Qwerky

Respuesta

13

Si el método de código hash se basa en el campo name, y luego cambiarlo después de añadir el objeto, entonces el segundo contains cheque utilizará el nuevo valor hash, y no encontrará el objeto que estabas buscando Esto es porque HashSet s busca por código hash, por lo que no se molestará en llamar al equals si falla la búsqueda.

La única manera de que esto funcionaría si es tenido no anulado equals (y por lo tanto se utilizó la igualdad de referencia por defecto) y tienes suerte y los códigos hash de los dos objetos son iguales. Pero este es un escenario poco probable realmente, y no debe confiar en él.

En general, se debe Nunca actualización de un objeto después de que se haya agregado a un HashSet si ese cambio también va a cambiar su código hash.

+0

por lo que es una copia de u agregado en el hashset? De lo contrario, creo que el objeto en el conjunto de nombres tendría name3 aswell – Ced

9

Dado que su nuevo User tiene un código de hash diferente, el HashSet sabe que no es igual.

HashSets almacenan sus elementos de acuerdo con sus códigos hash.
El HashSet sólo llamar equals si encuentra un elemento con el mismo código hash, para asegurarse de que los dos elementos son en realidad iguales (en oposición a una colisión de hash)

+1

De hecho, llama a igual sólo si hashCode son iguales. Esto significa que si actualizo User, que lo cambio hashCode, la matriz anidada que contiene la Entrada asociada a sus hashCodes no se actualizará. Por lo tanto, iterar sobre esta matriz no devolvería la entrada con el mismo hashCode. Debería funcionar si hashCode siempre devuelve 0) – user12384512

+3

Correcto. En general, es una mala idea colocar objetos mutables en un HashSet. Si haces 'hashCode()' return '0', perderás todos los beneficios de rendimiento del HashSet, y terminarás con la colección más lenta que puedas obtener. – SLaks

+0

Lo sé, esto es solo un ejemplo – user12384512