Copia superficial de un mapa en Java


Según lo entiendo, hay un par de maneras (tal vez otras también) para crear una copia superficial de un Map 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 forma preferida sobre la otra, y si es así, ¿por qué?

Una cosa que vale la pena mencionar es que la segunda forma da una advertencia de "Lanzamiento sin control". Así que tienes que añadir @SuppressWarnings("unchecked") para sortearlo, lo cual es un poco irritante (ver más abajo).

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

3 answers

Siempre es mejor copiar usando un constructor de copia. clone() en Java está roto (ver SO: Cómo sobrescribir correctamente el método de clonación?).

Josh Bloch sobre el diseño - Copy Constructor versus Clonación

Si has leído el artículo sobre la clonación en mi libro, especialmente si lees entre líneas, sabrás que creo que clone está profundamente roto. [... Es una pena que Cloneable esté roto, pero sucede.

Bloch (que por cierto, diseñó y implementó el marco de recopilación) incluso fue más allá al decir que solo proporciona el método clone() solo "porque la gente lo espera". En realidad 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 copias, pero esa es una discusión completamente diferente.

 105
Author: polygenelubricants,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:34

Ninguno de los dos: el constructor al que se refiere está definido para la implementación HashMap de un Mapa Map, (así como para otros) pero no para la interfaz del Mapa en sí (por ejemplo, considere la implementación Provider de la interfaz del Mapa: no encontrará ese constructor).

Por otro lado, no es aconsejable usar el método clone(), como explicó Josh Bloch.

Con respecto a la interfaz del mapa (y de su pregunta, en la que se pregunta cómo copiar un mapa, no un HashMap), debe usar Map # putAll():

Copia todas las asignaciones del mapa especificado a este mapa (operación opcional). El efecto de esta llamada es equivalente al de llamar a put (k, v) en este mapa una vez por cada asignación de la tecla 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);
 55
Author: Luca Fagioli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-24 17:41:18

Copiar un mapa sin conocer su implementación:

static final Map shallowCopy(final Map source) throws Exception {
    final Map newMap = source.getClass().newInstance();
    newMap.putAll(source);
    return newMap;
}
 11
Author: Terris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-04 04:10:03