在 Java 中映射的浅拷贝

据我所知,有几种方法(也许还有其他方法)可以在 Java 中创建 Map的浅拷贝:

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();

一种方法优于另一种方法,如果是这样,为什么?

值得一提的是,第二种方法会提供“ UncheckCast”警告。因此,你必须添加 @SuppressWarnings("unchecked")来绕过它,这是一个有点恼人(见下文)。

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

It's always better to copy using a copy constructor. clone() in Java is broken (see SO: How to properly override clone method?).

Josh Bloch on Design - Copy Constructor versus Cloning

If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. [...] It's a shame that Cloneable is broken, but it happens.

Bloch (who by the way, designed and implemented the Collection framework) even went further in saying that he only provides the clone() method just "because people expect it". He does NOT actually recommend using it at all.


I think the more interesting debate is whether a copy constructor is better than a copy factory, but that's a different discussion altogether.

Neither of the two: the constructor that you are referring to is defined for the HashMap implementation of a Map, (as well as for others) but not for the Map interface itself (for example, consider the Provider implementation of the Map interface: you will not find that constructor).

On the other hand it is not advisable to use the clone() method, as explained by Josh Bloch.

In respect of the Map interface (and of your question, in which you ask how to copy a Map, not a HashMap), you should use Map#putAll():

Copies all of the mappings from the specified map to this map (optional operation). The effect of this call is equivalent to that of calling put(k, v) on this map once for each mapping from key k to value v in the specified map.

Example:

// 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);

Copy a map without knowing its implementation:

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