代码之家  ›  专栏  ›  技术社区  ›  walnutmon

Java防御性拷贝

  •  1
  • walnutmon  · 技术社区  · 14 年前

    我见过这样的防御性副本

    void someMethod(Date d) {
        myDate = new Date( d.getTime() );
    }
    

    clone() 不会在所有情况下都起作用,但我不明白为什么。

    4 回复  |  直到 10 年前
        1
  •  7
  •   Scott Smith    8 年前

    Copy Constructor versus Cloning

    比尔·维纳斯: 在您的书中,您建议使用复制构造函数而不是实现 Cloneable clone . 你能详细说明一下吗?

    乔希·布洛赫: 如果你读过我书中关于克隆的内容,特别是你读到字里行间的内容,你就会知道我认为克隆已经被彻底打破了。有一些设计缺陷,其中最大的是 接口没有 克隆 方法。这意味着它根本不起作用:做点什么 可克隆的 没有说你能用它做什么。相反,它说的是它能在内部做些什么。上面说如果你打电话 super.clone Object 克隆 方法,此方法将返回原始的字段副本。

    但它并没有说明您可以对实现 可克隆的 克隆 操作。如果我有一个数组 ,您可能认为我可以运行该数组并克隆每个元素以生成该数组的深度副本,但我不能。您不能向 可克隆的 方法,因为 可克隆的 克隆 对象 可克隆的 克隆 方法,编译器会说您正在尝试调用受保护的 对象上的方法。

    事实上,您并没有通过实现为您的客户提供任何功能 可克隆的 为公众提供 克隆 可克隆的 LinkedList 变成一个 ArrayList

    对象 这个方法很棘手。它基于字段副本,而且是“超语言的”,它创建一个对象而不调用构造函数。不能保证它保留构造函数建立的不变量。这些年来,太阳内外都有很多虫子,这是因为如果你打电话给 超级克隆

    我用的东西很少 可克隆的 不再。我经常提供公共服务 方法,因为人们期望它。我没有实现抽象类 可克隆的 在扩展(或实现)抽象类(或接口)的所有类上。这是一个真正的负担,几乎没有好处。

    道格李更进一步。他告诉我他不使用 克隆 复制数组,因为这通常是最快的方法。但是Doug的类型根本没有实现 可克隆的 不再。他已经放弃了。我认为这不是不合理的。

    可克隆的 可克隆的 是一个弱点,我认为人们应该意识到它的局限性。

        2
  •  3
  •   catch23    10 年前

    clone() 只在某些类中有意义地实现了,因为在克隆过程中涉及到很多JVM或编译器不能为您做出的决策(例如,浅拷贝与深拷贝)。有些人还认为Java中的整个概念是不完整的,因此很少使用。

    然而,最终的结果是许多类不能被克隆。在这些情况下,用户通过基于另一个对象生成和初始化一个对象来克隆它们。

    然而 Date 类实现 Cloneable 因此,在这种特定情况下,与仅使用“复制构造函数”相比,实际上没有什么好处。

    克隆更可取的一种情况是在处理类层次结构时。假设您将数学表达式表示为表达式子类型树,其中引用 表情。

    假设在这种情况下它是一个加号。您可以在引用表达式时调用clone,但实际得到的是Plus的一个新实例。对于构造函数,您不能真正做到这一点,因为您的表达式可以是接口或抽象类。

        3
  •  1
  •   Thilo    14 年前

    没有一种简单的方法可以制作出一个完全相同的副本。

    另一种方法是序列化/反序列化,但并非所有类都支持序列化。

        4
  •  0
  •   Tom Hawtin - tackline    14 年前

    从移动代码安全的角度来看, clone

    @Override public Date clone() {
        return this; // Ha!
    }
    

    即使您不关心安全性,您也可以想象程序员“聪明”导致代码中出现错误报告。

    将返回完全相同的运行时类型也会导致实现问题。