【问题标题】:Shallow copy of a Map in JavaJava中地图的浅拷贝
【发布时间】:2011-01-22 08:15:34
【问题描述】:

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

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

值得一提的是,第二种方式会给出“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();
}

【问题讨论】:

  • 在较新版本的 Java 中(准确地说是从 Java 10 开始),您可以使用 Map.copyOf 静态工厂方法。但请注意,它返回一个不可修改的地图!

标签: java map clone shallow-copy


【解决方案1】:

使用复制构造函数进行复制总是更好。 Java 中的 clone() 已损坏(参见 SO:How to properly override clone method?)。

Josh Bloch on Design - Copy Constructor versus Cloning

如果你读过我书中关于克隆的内容,尤其是如果你读到字里行间,你就会知道我认为clone 被深深地破坏了。 [...] 很遗憾 Cloneable 坏了,但它确实发生了。

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


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

【讨论】:

  • 是的,这是本书中我最喜欢的部分之一。
  • 我不想说 clone() 坏了。我更愿意说克隆是一个糟糕的设计决定,如果你不正确使用它会伤害你很多。此外,您可能永远不会相信其他人的 clone() 方法。所以我们最终是相似的,尽量避免它,但它没有坏。
  • 不使用复制 ctor 要求您知道要复制的 Map 的实现吗?似乎是不必要的限制。
  • “他只提供 clone() 方法只是“因为人们期望它”——来源?
【解决方案2】:

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

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

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

将所有映射从指定映射复制到此映射 (可选操作)。这个调用的效果相当于 对于从键 k 到的每个映射,在此映射上调用一次 put(k, v) 指定映射中的值 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);

【讨论】:

  • 那么澄清一下:如果您知道正在复制具有复制构造函数的Map的实现,则没有理由不这样做那么使用复制构造函数呢?
  • 没错,你甚至可以反过来想:如果你使用putAll,你不需要知道你使用的Map实现是否有复制构造函数与否。因此,任何Map 实现的仅复制构造函数都是多余的。
  • 当然,虽然我通常更喜欢 1-liners 而不是 2-liners。 ;)
【解决方案3】:

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

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

【讨论】:

  • 考虑添加&lt;K,V&gt;类型参数以帮助确保类型安全。
  • 没有零参数构造函数的地图呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 2012-04-12
  • 2011-03-24
  • 2016-12-03
  • 1970-01-01
  • 2015-01-13
相关资源
最近更新 更多