¿Son las claves mutables de hashmap una práctica peligrosa?

Resuelto donnyton asked hace 13 años • 10 respuestas

¿Es una mala práctica utilizar objetos mutables como claves Hashmap? ¿Qué sucede cuando intentas recuperar un valor de un Hashmap usando una clave que se ha modificado lo suficiente como para cambiar su código hash?

Por ejemplo, dado

class Key
{
    int a; //mutable field
    int b; //mutable field

    public int hashcode()
        return foo(a, b);
    // setters setA and setB omitted for brevity
}

con codigo

HashMap<Key, Value> map = new HashMap<Key, Value>();

Key key1 = new Key(0, 0);
map.put(key1, value1); // value1 is an instance of Value

key1.setA(5);
key1.setB(10);

¿Qué pasa si ahora llamamos map.get(key1)? ¿Es esto seguro o aconsejable? ¿O el comportamiento depende del idioma?

donnyton avatar Oct 21 '11 03:10 donnyton
Aceptado

Muchos desarrolladores respetados, como Brian Goetz y Josh Bloch, han señalado que:

Si el valor hashCode() de un objeto puede cambiar según su estado, entonces debemos tener cuidado al usar objetos como claves en colecciones basadas en hash para asegurarnos de que no permitimos que su estado cambie cuando se usan como claves hash. . Todas las colecciones basadas en hash asumen que el valor hash de un objeto no cambia mientras está en uso como clave en la colección. Si el código hash de una clave cambiara mientras estaba en una colección, podrían producirse algunas consecuencias impredecibles y confusas. Por lo general, esto no es un problema en la práctica; no es una práctica común usar un objeto mutable como una Lista como clave en un HashMap.

aleroot avatar Oct 29 '2011 21:10 aleroot

Esto no es seguro ni aconsejable. El valor asignado por key1 nunca se puede recuperar. Al realizar una recuperación, la mayoría de los mapas hash harán algo como

Object get(Object key) {
    int hash = key.hashCode();
    //simplified, ignores hash collisions,
    Entry entry = getEntry(hash);
    if(entry != null && entry.getKey().equals(key)) {
        return entry.getValue();
    }
    return null;
}

En este ejemplo, key1.hashcode() ahora apunta al depósito incorrecto de la tabla hash y no podrá recuperar el valor1 con la clave1.

Si hubieras hecho algo como,

Key key1 = new Key(0, 0);
map.put(key1, value1);
key1.setA(5);
Key key2 = new Key(0, 0);
map.get(key2);

Esto tampoco recuperará el valor1, ya que la clave1 y la clave2 ya no son iguales, por lo que esta verificación

    if(entry != null && entry.getKey().equals(key)) 

fallará.

sbridges avatar Oct 24 '2011 05:10 sbridges