2010-03-01 21 views
93

lo que tengo entendido, hay un par de maneras (tal vez otros también) para crear una copia superficial de un Map en Java:copia superficial de un mapa en Java

Map<String, Object> data = new HashMap<String, Object>(); 
Map<String, Object> shallowCopy; 

// first way 
shallowCopy = new HashMap<String, Object>(data); 

// second way 
shallowCopy = (Map<String, Object>) ((HashMap<String, Object>) data).clone(); 

es una manera preferida sobre el otro, y si es así, ¿por qué?

Una cosa que vale la pena mencionar es que la segunda forma da una advertencia de "rechazo no verificado". Por lo tanto, debe agregar @SuppressWarnings("unchecked") para evitarlo, lo cual es un poco irritante (vea a continuación).

@SuppressWarnings("unchecked") 
public Map<String, Object> getDataAsMap() { 
    // return a shallow copy of the data map 
    return (Map<String, Object>) ((HashMap<String, Object>) data).clone(); 
} 

Respuesta

98

Siempre es mejor copiar usando un constructor de copia. clone() en Java está roto (ver SO: How to properly override clone method?).

Josh Bloch on Design - Copy Constructor versus Cloning

Si usted ha leído el artículo sobre la clonación en mi libro, especialmente si se lee entre líneas, ustedes sabrán que yo creo que es clone profundamente roto. [...] Es una pena que Cloneable esté roto, pero sucede.

Bloch (que por cierto, diseñado e implementado el Marco de la colección), incluso fue más lejos al decir que sólo proporciona el método clone() simplemente "porque la gente espera que". Él realmente NO recomienda usarlo en absoluto.


creo que el debate más interesante es si un constructor de copia es mejor que una fábrica de copia, pero eso es una discusión totalmente diferente.

+2

agradable respuesta, gracias. – dcp

+0

Sí, esta es una de mis partes favoritas del libro. – polygenelubricants

+1

No me gusta decir que el clon() está roto. Prefiero decir que el clon fue una decisión de diseño terrible y puede hacerte mucho daño si no lo usas correctamente.Además, es posible que nunca confíes en los métodos de otras personas clone(). Así que terminamos de manera similar, tratamos de evitarlo, pero no está roto. – santiagobasulto

49

Ninguno de los dos: el constructor que se está refiriendo a se define para la HashMap implementación de un Map, (así como para los demás) pero no para la propia interfaz de mapa (por ejemplo, considerar la Provider aplicación de la Interfaz de mapa: no encontrarás ese constructor).

Por otro lado, no es aconsejable utilizar el método clone(), como explica Josh Bloch.

Con respecto a la interfaz de mapa (y de su pregunta, en el que solicita a la forma de copiar un mapa, no un HashMap), se debe utilizar Map#putAll():

Copia todos los mapeos de la especificada mapa a este mapa (operación opcional). El efecto de esta llamada es equivalente al de llamando a put (k, v) en este mapa una vez para cada asignación desde la clave k a valor v en el mapa especificado.

Ejemplo:

// HashMap here, but it works for every implementation of the Map interface 
Map<String, Object> data = new HashMap<String, Object>(); 
Map<String, Object> shallowCopy = new HashMap<String, Object>(); 

shallowCopy.putAll(data); 
+2

Entonces aclare: si * sabe * está copiando * a * una implementación de 'Mapa' que tiene un constructor de copia, entonces no hay razón para no usar el constructor de copia. –

+2

Exactamente, e incluso puede pensar al revés: si usa 'putAll', _no necesita saber_ si la implementación' Map' que está utilizando tiene un constructor de copia o no. Un copiador simplemente constructor de cualquier implementación de 'Mapa' es por lo tanto redundante. –

+1

Claro, aunque generalmente me gusta 1-liners mejor que 2-liners. ;) –

7

Copiar un mapa sin conocer su aplicación:

static final Map shallowCopy(final Map source) throws Exception { 
    final Map newMap = source.getClass().newInstance(); 
    newMap.putAll(source); 
    return newMap; 
} 
+2

Considere agregar parámetros de tipo '' para ayudar a garantizar la seguridad del tipo. – Barett

+0

¿Qué pasa con los mapas sin constructores de argumento cero? –

Cuestiones relacionadas