2009-05-08 13 views

Respuesta

28

El documentations dice:

Un uso típico de esta clase es gráfico de objetos transformaciones de topología de preservación, como serialización o profunda-copia. Para realizar dicha transformación , un programa debe mantener una "tabla de nodos" que guarde la pista de todas las referencias de objeto que ya se hayan procesado. La tabla de nodos no debe equiparar distintos objetos aunque resulten ser iguales. Otro uso típico de esta clase es mantener objetos proxy. Por ejemplo, una instalación de depuración podría desear mantener un objeto proxy para cada objeto en el programa que está siendo depurado.

+3

Vengo de la documentación, buscando una explicación en SO – Rockstar5645

32

Cuando desee que sus claves no se puedan comparar por equals, pero por ==, utilizará IdentityHashMap. Esto puede ser muy útil si realiza un gran manejo de referencias, pero está limitado solo a casos muy especiales.

+1

El comportamiento de la comparación ison es el boleto aquí. He utilizado HashMaps "Identity" para almacenar metadatos que deberían estar asociados con un objeto en particular. La igualdad de valores de los objetos posiblemente sea la misma. Sin embargo, se debe tener cuidado para asegurar que el original se conserve mientras se requiera la búsqueda [directa], y se debe tener cuidado para evitar la "fuga" de memoria. –

+2

Además, como la identidad invariante (o == o => verdadero, para cualquier o), IdentityHashMap se puede usar * incluso si los objetos clave están mutados *. Pero no estás usando teclas mutables ... ¿verdad? (Tal vez debería ir a sentarse en una esquina y llorar.) –

12

Se trata de una experiencia práctica de mí:

IdentityHashMap deja una huella de memoria mucho menor en comparación con HashMap para grandes cardinalidades.

19

Un caso en el que puede usar IdentityHashMap es si sus claves son objetos de clase. ¡Esto es aproximadamente un 33% más rápido que el HashMap para obtener! Probablemente usa menos memoria también.

+1

¿Tiene alguna fuente/punto de referencia para respaldar esa afirmación? – kgdinesh

+1

@DineshBabu Nada realmente concluyente. Hay [este] (http://www.java-gaming.org/index.php?topic=21395.0) pero, por supuesto, las microbenchmarks varían según la JVM, el tamaño del mapa, la calidad del código hash, las implementaciones, la fase de la luna, etc. IdentityHashMap evita objetos de entrada (tiene impacto de GC) y usa == para la comparación, por lo que se espera que funcione un poco mejor. Puede que le guste mi [cuckoo map] (https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/utils/ObjectMap.java), que ha tenido un uso generalizado en libgdx y Kryo. Hay una serie de otros mapas en el mismo paquete, incluido IdentityMap. – NateS

16

HashMap crea objetos de entrada cada vez que agrega un objeto, lo que puede poner mucho estrés en el GC cuando tiene muchos objetos. En un HashMap con 1.000 objetos o más, terminará usando una buena parte de su CPU con solo las entradas de limpieza de GC (en situaciones como la búsqueda de rutas u otras colecciones de un solo uso que se crean y luego se limpian). IdentityHashMap no tiene este problema, por lo que terminará siendo significativamente más rápido.

Ver un punto de referencia aquí: http://www.javagaming.org/index.php/topic,21395.0/topicseen.html

+0

Jeje, soy el mismo Nate. – NateS

+0

:-) ¡Ajá! Ve JGO. – Eli

3

Un caso importante es cuando se trata de los tipos de referencia (en contraposición a los valores) y que realmente desea que el resultado correcto. Los objetos maliciosos pueden haber anulado los métodos hashCode y equals haciendo cualquier tipo de travesura. Desafortunadamente, no se usa con la frecuencia que debería. Si los tipos de interfaz con los que está tratando no anulan hashCode y equals, generalmente debería ir por IdentityHashMap.

12

También puede utilizar el IdentityHashMap como un mapa propósito generalsi puede asegurarse de que los objetos que utiliza como claves serán iguales si y sólo si sus referencias son iguales.

¿Para qué beneficio? Obviamente será más rápido y utilizará menos memoria que utilizando implementaciones como HashMap o TreeMap.


En realidad, hay un buen montón de casos en los que esta se encuentra. Por ejemplo:

  • Enum s. Aunque para las enumeraciones hay incluso una mejor alternativa: EnumMap
  • Class objetos. También son comparables por referencia.
  • Internado String s. O bien al especificarlos como literales o llamando al String.intern() en ellos.
  • Instancias en caché. Algunas clases proporcionan almacenamiento en caché de sus instancias. Por ejemplo se cita el javadoc de Integer.valueOf(int):

    Este método será siempre valores de caché en el rango de -128 a 127, inclusive ...

  • Ciertas bibliotecas/marcos gestionará exactamente una instancia del tipo ceratin, por ejemplo Spring beans.
  • tipos Singleton. Si utiliza istances de tipos que están construidos con el patrón Singleton, también puede estar seguro de que (a lo sumo) existe una instancia de ellos y, por lo tanto, la prueba de igualdad de referencia calificará para la prueba de igualdad.
  • Cualquier otro tipo en el que explícitamente se ocupe de usar solo las mismas referencias para acceder a los valores que se utilizaron para poner valores en el mapa.


Para demostrar el último punto:

Map<Object, String> m = new IdentityHashMap<>(); 

// Any keys, we keep their references 
Object[] keys = { "strkey", new Object(), new Integer(1234567) }; 

for (int i = 0; i < keys.length; i++) 
    m.put(keys[i], "Key #" + i); 

// We query values from map by the same references: 
for (Object key : keys) 
    System.out.println(key + ": " + m.get(key)); 

salida será, como se esperaba (porque utilizamos las mismas Object referencias para consultar los valores del mapa):

strkey: Key #0 
[email protected]: Key #1 
1234567: Key #2