资讯专栏INFORMATION COLUMN

Java 作者谈克隆方法的实现

gaomysion / 596人阅读

摘要:不合规的代码示例合规解决方案参阅复制构造函数与克隆也可以参阅应该实现克隆覆盖的类应为并调用下面为引文翻译谈设计与作者的对话,作者首次在上发表,年月日复制构造函数与克隆在你的书中,你建议使用复制构造函数而不是实现和编写。

今天在用 sonar 审核代码, 偶然看到下面的提示:

关于这个的提示大意是:

“克隆”不应该被覆盖, 属坏味道, 阻断型错误
约书亚•布洛赫表示,许多人在 Java 中对 clone 方法 和 Cloneable 接口存在误解,很大程度上是因为重写 clone 方法的规则很棘手, 且出错难以纠正。
Object 的 clone 方法非常棘手。它基于属性复制,而且是“超语言”。它创建一个对象而不调用构造函数。无法保证它保留构造函数创建的不变量。多年来,在 Sun 公司内外都存在许多错误,这源于这样一个事实,即如果你只是反复调用 super.clone 直到克隆了一个对象,那么你就拥有了一个浅层的对象副本。克隆通常与正在克隆的对象共享状态。如果该状态是可变的,则您没有两个独立的对象。如果您修改一个,另一个也会更改。突然之间,你会得到随机行为。

所以, 应该使用复制构造函数或复制工厂。

clone 无论是否实现 Cloneable 接口,此规则在被覆盖时都会引发问题。

不合规的代码示例

public class MyClass {
  // ...

  public Object clone() { // Noncompliant
    //...
  }
}

合规解决方案

public class MyClass {
  // ...

  MyClass (MyClass source) {
    //...
  }
}

参阅
《复制构造函数与克隆》
也可以参阅

S2157 - “Cloneables”应该实现“克隆”
S1182 - 覆盖“clone”的类应为“Cloneable”并调用“super.clone()”

下面为引文翻译

Josh Bloch 谈设计
与《Effective Java》作者的对话,Josh Bloch

作者 Bill Venners
首次在JavaWorld上发表,2002年1月4日

复制构造函数与克隆

Bill Venners: 在你的书中,你建议使用复制构造函数而不是实现Cloneable和编写clone。你能详细说明吗?

Josh Bloch:如果你已经阅读了我的书中关于克隆的章节,特别是如果你看得仔细的话,你就会知道我认为克隆已经完全坏掉的东西。有一些设计缺陷,其中最大的一个是 Cloneable 接口没有 clone方法。这意味着它根本不起作用:实现了 Cloneable 接口并不说明你可以用它做什么。相反,它说明了内部可能做些什么。它说如果通过super.clone 反复调用它最终调用 Object 的 clone 方法,这个方法将返回原始的属性副本。

但它没有说明你可以用一个实现 Cloneable 接口的对象做什么,这意味着你不能做多态 clone 操作。如果我有一个 Cloneable 数组,你会认为我可以运行该数组并克隆每个元素以制作数组的深层副本,但不能。你不能强制转换对象为 Cloneable 接口并调用 clone 方法,因为 Cloneable 没有public clone 方法,Object 类也没有。如果您尝试强制转换 Cloneable 并调用该 clone 方法,编译器会说您正在尝试在对象上调用受保护的clone方法。

事实的真相是,您不通过实施 Cloneable 和提供 clone 除复制能力之外的公共方法为您的客户提供任何能力。如果您提供具有不同名称的copy操作, 怎么也不次于去实现 Cloneable 接口。这基本上就是你用复制构造函数做的事情。复制构造方法有几个优点,我在本书中有讨论。一个很大的优点是可以使副本具有与原始副本不同的实现。例如,您可以将一个 LinkedList 复制到 ArrayList。

Object 的 clone 方法是非常棘手的。它基于属性复制,而且是“超语言”。它创建一个对象而不调用构造函数。无法保证它保留构造函数建立的不变量。多年来,在Sun内外存在许多错误,这源于这样一个事实,即如果你只是super.clone 反复调用链直到你克隆了一个对象,那么你就拥有了一个浅层的对象副本。克隆通常与正在克隆的对象共享状态。如果该状态是可变的,则您没有两个独立的对象。如果您修改一个,另一个也会更改。突然之间,你会得到随机行为。

我使用的东西很少实现 Cloneable。我经常提供实现类的 clone 公共方法,仅是因为人们期望有。我没有抽象类实现 Cloneable,也没有接口扩展它,因为我不会将实现的负担 Cloneable 放在扩展(或实现)抽象类(或接口)的所有类上。这是一个真正的负担,几乎没有什么好处。

Doug Lea 走得更远。他告诉我 clone 除了复制数组之外他不再使用了。您应该使用 clone 复制数组,因为这通常是最快的方法。但 Doug 的类根本就不再实施 Cloneable了。他放弃了。而且我认为这并非不合理。

这是一个耻辱, Cloneable 接口坏掉了,但它发生了。最初的 Java API在紧迫的期限内完成,以满足市场窗口收紧的需求。最初的 Java 团队做了不可思议的工作,但并非所有的 API 都是完美的。 Cloneable 是一个弱点,我认为人们应该意识到它的局限性。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73848.html

相关文章

  • 给自己博客网站加上酷炫初音未来音乐游戏?

    摘要:嘻嘻大功告成计划完美实现参考文献乐柔嘴巴反向代理学习及实例笔记利用的反向代理克隆生成镜像网站中间人攻击原作者的原始游戏页面上国人搬运的开源镜像特别致谢执着的少年 先前在某个Q群里有位网友发了个链接,一点进去,发现是个极度让人耳目一新的初音未来音乐网页游戏。 为了让有幸看到这篇文章的看官也来体会下本人第一次玩时的激动,抛个链接——乐柔嘴巴。链接的具体地址是blog.eunji.cn/m...

    caozhijian 评论0 收藏0
  • 给自己博客网站加上酷炫初音未来音乐游戏?

    摘要:嘻嘻大功告成计划完美实现参考文献乐柔嘴巴反向代理学习及实例笔记利用的反向代理克隆生成镜像网站中间人攻击原作者的原始游戏页面上国人搬运的开源镜像特别致谢执着的少年 先前在某个Q群里有位网友发了个链接,一点进去,发现是个极度让人耳目一新的初音未来音乐网页游戏。 为了让有幸看到这篇文章的看官也来体会下本人第一次玩时的激动,抛个链接——乐柔嘴巴。链接的具体地址是blog.eunji.cn/m...

    qylost 评论0 收藏0
  • 给自己博客网站加上酷炫初音未来音乐游戏?

    摘要:嘻嘻大功告成计划完美实现参考文献乐柔嘴巴反向代理学习及实例笔记利用的反向代理克隆生成镜像网站中间人攻击原作者的原始游戏页面上国人搬运的开源镜像特别致谢执着的少年 先前在某个Q群里有位网友发了个链接,一点进去,发现是个极度让人耳目一新的初音未来音乐网页游戏。 为了让有幸看到这篇文章的看官也来体会下本人第一次玩时的激动,抛个链接——乐柔嘴巴。链接的具体地址是blog.eunji.cn/m...

    booster 评论0 收藏0
  • 自动化测试工具

    摘要:自己写一个程序来自动生成测试数据,因为每个个人作业的要求不一样,自动化框架无法对每种程序都生成测试数据,目前只支持生成按规则生成随机的字符串测试集。 作者:Grey...

    tuniutech 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<