109

据我了解,有几种方法(也许还有其他方法)可以Map在 Java 中创建 a 的浅表副本:

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

一种方式优于另一种方式,如果是,为什么?

值得一提的是,第二种方式给出了“Unchecked Cast”警告。所以你必须添加@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();
}
4

3 回答 3

107

使用复制构造函数进行复制总是更好。clone()在 Java 中已损坏(请参阅 SO:如何正确覆盖克隆方法?)。

Josh Bloch 谈设计 - 复制构造函数与克隆

如果你读过我书中关于克隆的项目,尤其是如果你读到字里行间,你就会知道我认为clone它被深深地破坏了。[...] 被打破是一种耻辱Cloneable,但它确实发生了。

Bloch(顺便说一句,他设计并实现了 Collection 框架)甚至进一步说他只提供clone()方法只是“因为人们期望它”。他实际上根本不推荐使用它。


我认为更有趣的争论是复制构造函数是否比复制工厂更好,但这完全是一个不同的讨论。

于 2010-03-01T15:27:31.000 回答
61

两者都不是:您所指的构造函数是为Map的HashMap实现(以及其他)定义的,但不是为 Map 接口本身定义的(例如,考虑 Map 接口的Provider实现:您将找不到该构造函数)。

另一方面clone(),正如 Josh Bloch 所解释的,不建议使用该方法。

关于 Map 接口(以及您的问题,您询问如何复制 Map,而不是 HashMap),您应该使用Map#putAll()

将所有映射从指定映射复制到此映射(可选操作)。这个调用的效果等同于对指定映射中从键 k 到值 v 的每个映射调用一次 put(k, v) 在这个映射上的效果。

例子:

// 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);
于 2013-02-01T17:28:36.003 回答
11

在不知道其实现的情况下复制地图:

static final Map shallowCopy(final Map source) throws Exception {
    final Map newMap = source.getClass().newInstance();
    newMap.putAll(source);
    return newMap;
}
于 2015-02-04T04:10:03.090 回答