gpt4 book ai didi

java - 为什么 CopyOnWriteArraySet 不实现 Cloneable 接口(interface),而 CopyOnWriteArrayList 实现?

转载 作者:行者123 更新时间:2023-11-29 07:29:20 26 4
gpt4 key购买 nike

在这个 bug report ,Doug Lea 写道(指的是 JDK 5.0 的预发布版本):

While CopyOnWriteArraySet is declared Cloneable, it fails to define public clone method.



但最终结果是 CopyOnWriteArraySet没有实现 Cloneable完全没有界面! (这在 Java SE 6、7 和 8 中是正确的。)
CopyOnWriteArraySet怎么样不同于 CopyOnWriteArrayList关于克隆?没有人想要克隆它是有充分理由的吗?

附言我了解 clone()不推荐, CopyOnWriteArraySet基于 CopyOnWriteArrayList内部。

最佳答案

在 secret 数据库中有一些关于此错误 (JDK-5055732) 的重要信息。我已在有关该错误的公开评论中发布了此信息,我将在此处复制它以回答此问题。

Problem

As explained in Josh Bloch's Effective Java, the Cloneable mechanism is not terribly well designed. In particular, it is impossible for a non-final class with a final reference field that needs to be unique for each object to satisfy the requirement that

x.clone().getClass() == x.getClass()

(when the class is subclassed)

CopyOnWriteArraySet, ConcurrentHashMap currently are specified to implement Cloneable. CopyOnWriteArraySet erroneously did not implement a public clone() method, while ConcurrentHashMap implemented a clone() method using a constructor, thereby not fulfilling the above requirement.

Doug Lea writes:

"Martin and Josh convinced me that we can't just add the one-line public Object clone() { return new CopyOnWriteArraySet(al); } because, as noted by Josh in Effective Java book, clone methods should not invoke constructors:

In practice, programmers assume that if they extend a class and call super.clone from within the subclass, the returned object will be an instance of the subclass. The only way that a superclass can provide this functionality is to return an object obtained by calling super.clone. If a clone method returns an object created by a normal constructor, it will not have the correct class. Therefore, if you override the clone method in a non-final class, you should always return an object obtained by invoking super.clone().

In general this means that any class with a blank final field will encounter problems because it needs to set the field inside clone. This is now possible inside JDK classes using the setAccessible loophole (see JMM list) but is ugly and slow. It seems like a better idea just to remove "implements Cloneable".

The ConcurrentHashMap class has exactly the same problem, and the same solution."

Solution

Remove "implements Cloneable" from the specification for CopyOnWriteArraySet, ConcurrentHashMap. Delete ConcurrentHashMap.clone()


上面的文字解释了一切,但它可能有点令人困惑,因为它解释了与不再可见的代码状态相关的事情,并且还假设了相当多的上下文知识。这是一个我认为可能更容易理解的解释。
克隆问题在 Joshua Bloch 的 Effective Java 第 11 条中有完整的解释。许多问题也包含在 elsewhere on Stack Overflow 中。 .简而言之,为了成功克隆,一个类必须
  • 实现Cloneable接口(interface)
  • 实现 public clone()方法
  • clone()方法,必须
  • 调用super.clone()进行实际克隆
  • 修改克隆对象,可能通过深度复制内部结构
  • 返回克隆对象


  • 从历史上看,所有集合实现都支持克隆。在 JDK 5.0 发布之前, CopyOnWriteArraySetConcurrentHashMap两者都实现了 Cloneable界面。但是 CopyOnWriteArraySet没有实现 public clone()方法,而 ConcurrentHashMap确实实现了 public clone()方法,它通过返回一个新构造的 ConcurrentHashMap 的实例来错误地执行此操作。 .这两个都是错误,是本错误报告的主题。
    事实证明, CopyOnWriteArraySet也不是 ConcurrentHashMap可以履行支持克隆的所有义务。因此,该错误的“修复”是让他们退出 Cloneable。契约(Contract)。
    原因 CopyOnWriteArraySet不能克隆的是它有一个final字段 al指向 CopyOnWriteArrayList存储实际元素。克隆不能与原始共享此状态,因此 clone()方法将需要复制(或克隆)支持列表并将其存储到字段中。但是 final 字段只能存储在构造函数中,而 clone()不是构造函数。实现者考虑并拒绝了英雄的努力,例如使用反射来编写最终字段。
    那么像这样的单行构造函数呢?
        public clone() { return new CopyOnWriteArraySet(al); }
    这里的问题是它违反了克隆契约(Contract)。如果 CopyOnWriteArraySet 的子类支持克隆,调用 clone()在那个子类上应该返回那个子类的一个实例。 clone()子类的方法会正确调用 super.clone()创建克隆。如果按照上面的方式实现,那将返回 CopyOnWriteArraySet 的实例。而不是子类的实例。因此,这将防止子类能够克隆自己。 ConcurrentHashMap 呢? ?它没有任何最终字段。嗯,当时确实如此,所以它正好遇到了从 clone() 中更新最终字段的问题。方法。 ConcurrentHashMap 的最新版本不再有最终字段。复制构造函数只需调用 putAll在 map 参数上,它懒惰地初始化所有字段。不能 clone()方法只需克隆、清空所有字段,然后调用 putAll() ?
    这似乎可行,但我怀疑它与内存模型相冲突。并非所有字段都是易变的。即使在重新初始化以指向副本之前所有字段都被清空,其他线程也可能会看到仍然指向原始映射的陈旧值。可能有一些方法可以避免这个问题,但我怀疑实现者认为提供可克隆性不值得付出额外的努力。

    关于java - 为什么 CopyOnWriteArraySet 不实现 Cloneable 接口(interface),而 CopyOnWriteArrayList 实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45212827/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com