Java 中映射的浅层副本

2022-08-31 09:38:03

据我所知,有几种方法可以(也许还有其他方法)在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();

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

值得一提的一件事是,第二种方式给出了“未检查的投射”警告。因此,您必须添加才能绕过它,这有点烦人(见下文)。@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();
}

答案 1

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

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

如果你读过我书中关于克隆的文章,特别是如果你在字里行间阅读,你就会知道我认为已经深深地破碎了。[...]这是一种被打破的耻辱,但它发生了。cloneCloneable

布洛赫(顺便说一句,他设计和实施了收集框架)甚至进一步说,他只是“因为人们期望它”而提供这种方法。他实际上根本不建议使用它。clone()


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


答案 2

两者都不是:您引用的构造函数是为MapHashMap实现(以及其他实现)定义的,而不是为Map接口本身定义的(例如,考虑Map接口的提供者实现:您将找不到该构造函数)。

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

关于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);