克隆ConcurrentHashMap

4
为什么我不能克隆ConcurrentHashMap
ConcurrentHashMap<String, String> test = new ConcurrentHashMap<String, String>();
    test.put("hello", "Salaam");

    ConcurrentHashMap<String, String> test2 = (ConcurrentHashMap<String, String> ) test.clone();

    System.out.println(test2.get("hello"));

如果我使用 HashMap 而不是 ConcurrentHashMap,它可以正常工作。

因为与HashMap不同,ConcurrentHashMap没有实现Cloneable。这一事实凸显了你的代码无法编译,即该方法不可用!!! - Andreas
1
@Andreas:尽管名字上看起来实现了Cloneable,并不意味着你支持clone,而支持clone也不需要你实现CloneableCloneable实际上没有clone作为公共方法。这是clone设计的一种奇怪缺陷。 - user2357112
支持 clone 需要实现 Cloneable 接口,@user2357112。"在一个没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法会导致抛出 CloneNotSupportedException 异常。" - https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html - Lew Bloch
@LewBloch:是的,但如果您在clone实现中不使用Object :: clone(有时是合理的),则不需要实现Cloneable。这甚至不像Comparable,如果您在不实现Comparable的情况下实现了compareTo,则会失去所有接受Comparable参数的库方法。使用clone的任何内容都不需要Cloneable,因为您无法clone一个Cloneable - user2357112
2个回答

14

AbstractMap 上的 clone() 方法不是用于复制的,它是一个内部方法,请注意 protected 关键字。

protected Object clone() throws CloneNotSupportedException {

HashMap 具有公共的 clone() 方法,但这并不意味着您应该使用它。此问题在《Effective Java: Analysis of the clone() method》中进行了进一步讨论。

创建集合副本的更灵活的方法是使用复制构造函数。利用这些函数可以从任何其他 Map 实现中创建出任何一个 Map 集合。

/**
 * Creates a new map with the same mappings as the given map.
 *
 * @param m the map
 */
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
ConcurrentHashMap<String, String> original = new ConcurrentHashMap<String, String>();
original.put("hello", "Salaam");

Map<String, String> copy = new ConcurrentHashMap<>(original);
original.remove("hello");
System.out.println(copy.get("hello"));

1
你建议的方法确实是线程安全的吗?请注意,如果原始映射是并发哈希映射。并且您尝试通过new HashMap(collection)克隆它。代码将进入循环for (Map.Entry<? extends K, ? extends V> e : m.entrySet())。因此,如果同时有人访问您的并发哈希映射并取走了一个键值对,您在迭代元素时可能会遇到问题。并发哈希映射的实现构造函数看起来并不安全...它只是循环遍历原始映射的条目集。所以再见爆炸。 - 99Sono

0
更优雅的方式是执行深度克隆。 如果您执行深度克隆,则可能存在这样一种情况,即您只复制并发哈希映射中存储的引用而不是实际对象。因此,在这种情况下,首选深度克隆,其中对象图中的对象被克隆。最简单的深度克隆方法之一是使用Apache Common Lang库-SerializationUtils#clone。
<dependency>
        <groupId>commons-lang</groupId>
        <artifactId>commons-lang</artifactId>
        <version>2.6</version>
    </dependency>

您可以使用SerializationUtils类的clone api执行深层克隆,方法如下 -
ConcurrentHashMap<String, Vertex> transposeVertexMap = (ConcurrentHashMap<String, Vertex>) SerializationUtils.clone(vertexMap);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接