iterar implementar funciona for como java hashmap

implementar - map set java



Java HashMap funciona pero containsKey no funciona (9)

Estoy tratando de encontrar una clave en un HashMap. Puedo imprimir la clave seleccionada usando ''get'', pero cuando uso ''containsKey'' en una declaración if, no se encuentra.

SÉ que la clave está presente en el Mapa, pero sigue siendo falsa. ¿Alguna gente de ideas?

Mi código:

public static boolean checkLowerStructuralSupport(Location location) { boolean hasSupport = false; Location supportingLocation = new Location(location.getX(), location.getY(), location.getZ() - 1); System.out.println(_levels.get(supportingLocation.getZ()).getLevelSites2().get(supportingLocation)); //works if (_levels.get(supportingLocation.getZ()).getLevelSites2().containsKey(supportingLocation)) { hasSupport = true; } else { hasSupport = false; } return hasSupport; }

Aquí está el código para la clase de ubicación:

public class Location { protected int _x; protected int _y; protected int _z; public Location(int xAxis, int yAxis, int zAxis) { this._x = xAxis; this._y = yAxis; this._z = zAxis; } public void equals() { //not implemented yet } public void HashCode() { //not implemented yet } public String toString() { String locationString = Integer.toString(_x) + Integer.toString(_y) + Integer.toString(_z); return locationString; } public void setX(int XAxis) { this._x = XAxis; } public int getX() { return this._x; } public void setY(int YAxis) { this._y = YAxis; } public int getY() { return this._y; } public void setZ(int ZAxis) { this._z = ZAxis; } public int getZ() { return this._z; } }


Como se describe aquí, debe anular el método de igualdad (Objeto) .

La razón por la cual get (Object) está funcionando es que HashMap calculará el Hash para su clase Location y devolverá el Object al que tiene asignado el hascode points.

containsKey (Object) calcula la tecla hash y obtiene el objeto al que apunta el hash. El objeto del HashMap se comparará con el Objeto que ingresó. Para estas comparaciones, se usa el método igual. Cuando no anula el método es igual, se devuelve verdadero cuando el objeto hace referencia a la misma instancia.

De HashMap

/** * Check for equality of non-null reference x and possibly-null y. */ static boolean eq(Object x, Object y) { return x == y || x.equals(y); }

Desde el objeto

public boolean equals(Object obj) { return (this == obj); }

Del javadoc de iguales

El método equals para la clase Object implementa la relación de equivalencia más discriminatoria posible en los objetos; es decir, para cualquier valor de referencia no nulo x e y, este método devuelve verdadero si y solo si xey se refieren al mismo objeto (x == y tiene el valor verdadero).

Tenga en cuenta que generalmente es necesario anular el método hashCode siempre que se anule este método, a fin de mantener el contrato general para el método hashCode, que establece que los objetos iguales deben tener códigos hash iguales.


Debe asegurarse de que la clase Location haya implementado correctamente sus hashCode() y hashCode() equals(Object) ( documentación ). Es decir, si dos objetos Location son efectivamente iguales, deberían compartir un código hash común y su método equals debería devolver true .


En la clase de ubicación , asegúrese de anular HashCode y equivale a métodos.

Si es así, ¿puede publicarlos?


Haga un pico en el código fuente para la implementación de HashMap. Both get y containsKey usan los métodos hasCode () y equals () de su objeto clave.

La única diferencia real, y como se señaló, es una verificación nula trivial, está en las comparaciones:

obtener:

((k = e.key) == key || key.equals(k))

containsKey:

((k = e.key) == key || (key != null && key.equals(k)))

donde e es de tipo Entrada para un HashMap.

Entonces, si no tiene implementaciones fuertes de hashCode () y / o equals (), tendrá un problema. Además, si tus claves fueron mutadas (veo que no declaraste que los campos de clase son definitivos) podrías tener un problema.

Toma el siguiente ejemplo:

public class HashMapTest { static class KeyCheck { int value; public KeyCheck(int value) { this.value = value; } public void setValue(int value) { this.value = value; } @Override public int hashCode() { return value; } @Override public boolean equals(Object o) { return ((KeyCheck)o).value == this.value; } } public static void main(String args[]) { HashMap<KeyCheck, String> map = new HashMap<KeyCheck, String>(); KeyCheck k1 = new KeyCheck(5); KeyCheck k2 = new KeyCheck(5); map.put(k1, "Success"); System.out.println("Key: " + k1 + " Get: " + map.get(k1) + " Contains: " + map.containsKey(k1)); System.out.println("Key: " + k2 + " Get: " + map.get(k2) + " Contains: " + map.containsKey(k2)); k1.setValue(10); System.out.println("Key: " + k1 + " Get: " + map.get(k1) + " Contains: " + map.containsKey(k1)); System.out.println("Key: " + k2 + " Get: " + map.get(k2) + " Contains: " + map.containsKey(k2)); } }

Esto se imprimirá:

Clave: HashMapTest $ KeyCheck @ 5 Get: Success contains: true
Clave: HashMapTest $ KeyCheck @ 5 Get: Success contains: true
Clave: HashMapTest $ KeyCheck @ a Obtener: null Contiene: falso
Clave: HashMapTest $ KeyCheck @ 5 Get: null Contiene: falso

Como puede ver, en este caso la mutabilidad hizo que cambiara hashCode (), lo que arruinó todo.


Lo único que puedo pensar que causará esto es si el estado de supportingLocation está mutando de algún modo entre la llamada get(...) y containsKey(...) .

Suponiendo que el fragmento de código que publicó es el código exacto que está causando problemas, el único lugar donde esto podría ocurrir es si uno de Location#getZ(...) , Location#hashCode() o Location#equals(Object) muta el estado de Location (o el constructor de ubicación, o uno de estos métodos, inicia un hilo que cambia aleatoriamente el estado de la instancia de ubicación, pero creo que podemos descartarlo).

¿Podría verificar que ninguno de los métodos anteriores está cambiando el estado de la instancia de supportingLocation ? Si bien no estoy familiarizado con la clase de Location sí, me atrevo a adivinar que una clase así sería idealmente inmutable.

Editar: Para aclarar, cuando digo que Location#getZ() etc no está mutando la ubicación, lo que quiero decir es:

Location x = new Location(1,2,3); Location y = new Location(1,2,3); boolean eq1 = x.equals(y); int hash1 = x.hashCode(); x.getZ(); // this should *not* mutate the state of x boolean eq2 = x.equals(y); int hash2 = x.hashCode();

Al final, eq1 debe ser igual a eq1, y hash1 debe ser igual a hash2. Si este no es el caso, getZ () está mutando el estado de x (o igual, o hashCode, o peor, esos métodos están completamente desactivados), y dará como resultado el comportamiento que observó.


Para evitar problemas, sus métodos equals() y hashCode() deben ser consistentes y cumplir con los requisitos (como se indica en otra parte).

Además, hashCode () no debe depender de miembros mutables, de lo contrario su código hash calculado puede cambiar, y esto afecta el funcionamiento interno de HashMap . Eso se revelará en la imposibilidad de recuperar material de las colecciones Hash* .


containsKey usa el método igual para comparar el param con las entradas en el conjunto de claves. Entonces la clase Location necesita tener un método igual que sea bueno. El método predeterminado es igual en java.lang.Object solo devuelve verdadero cuando ambos objetos son el mismo objeto. En este caso, probablemente tenga 2 instancias diferentes que necesiten ser comparadas y necesite un método de igual a medida.


Both get() y containsKey() están utilizando el método hashCode() la clase Location . El método equals() no se llama a menos que haya una colisión hash. (por lo tanto, get () de HashMap no usará equals() en cada situación).

Para su clase de Location , ¿por casualidad implementó su propia versión de hashCode() ? El método hashCode() debe implementarse cuidadosamente. Joshua Bloch describió todos los detalles en el libro Effective Java , partes de las cuales están en línea ... Buscaré el enlace a esos capítulos de muestra: Effective Java Sample Chapters . Quieres el capítulo 3.

Como pregunté en el comentario a la pregunta, ¿de dónde _levels tu variable _levels ? No veo que se declare dentro de ese método y su nombre (prefijo de subrayado, ¿está importando esa convención de algún otro idioma?) Sugiere que "vive" fuera de este método. Tal vez otro código lo está cambiando durante la ejecución? Por favor, háganos saber cuándo lo resuelve; el suspenso me está matando.


Creo que alguna vez necesitas el código hash y otras veces no, así que creo que de esta manera puedes pasar el código hash comprobando cuando quieras comprar cambiando el código hash para todos los objetos que quieras 0

public class sample(){ @JsonIgnore private int hashCode = super.hashCode(); public void setHashCode(int hashCode){ this.hashCode = hashCode; } @Override public int hashCode(){ return this.hashCode; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final ReflectObject other = (ReflectObject) obj; if (this.hashCode != other.hashCode) { return false; } return true; } }