在java中需要克隆对象的原因是什么?

时间:2014-05-14 02:34:52

标签: java cloneable

我正在阅读Joshua Bloch的Effective Java。在那里,他谈到不使用Clonable接口。我有点像菜鸟,所以我的问题是,什么是代码中需要克隆的用例?有人能给出一个粘性的例子,以便我能掌握这个概念吗?

4 个答案:

答案 0 :(得分:5)

clone()接口提供了一种创建对象“浅”副本的机制。也就是说,默认情况下,将为副本分配更多内存,并将原始文件的每个部分复制到副本中。相反,将对象实例简单分配给变量将导致对同一对象的附加引用。虽然克隆对象本身就是一个真正的副本,但它包含的元素默认是对原始引用的元素的引用。如果需要真正的“深层”副本,则clone()方法也需要专门用于创建其成员的克隆。

clone()接口的一个可能用例是实现对象的版本历史记录,以允许回滚到它的旧版本。这可以在事务系统中使用,例如数据库。

另一个用例是实现copy-on-write,当对象的用户只提供对象的只读版本时,这可能很有用。

  

*修正克隆的说明,感谢和荣誉newacct

答案 1 :(得分:2)

来自维基百科Prototype pattern

  

...如果要在运行时创建另一个 true copy ,则需要clone() 对象您正在克隆的对象的em>。 True copy 表示新创建的Object的所有属性应与您要克隆的Object相同。如果您可以使用 new 实例化该类,您将获得一个具有所有属性作为其初始值的Object。例如,如果您正在设计用于执行银行帐户交易的系统,那么您可能需要制作包含帐户信息的对象的副本,对其执行事务,然后用修改后的对象替换原始对象。在这种情况下,您可能希望使用clone()而不是新的。

答案 2 :(得分:1)

在Java中克隆对象有很好的理由。请考虑以下代码:

MyObj first = new MyObj(someOwner, someTag, someInt);
MyObj second = first;

在这种情况下,我们只是复制该对象的引用(内存地址)。变量第一个第二个都指向MyObj类的同一个实例。 clone()方法应该实现的是所谓的深层复制。当然,这取决于实现:克隆方法的开发人员需要确保深层副本实际上是实现的目标。所以,代码:

MyObj third = (MyObj) first.clone();

在这种情况下,clone()的作用是遍历所有第一个的实例成员并复制/克隆这些成员,并使用这些值创建一个全新的MyObj实例。然后它返回对新实例的引用,因此第三是第一个的副本,而不仅仅是对同一实例的引用。

在评论中回答您的问题时,这取决于您的实现,无论clone是否创建成员变量的新克隆,还是仅仅复制引用。考虑MyObj示例类的以下实现,假设还存在类Person和NameTag。如果克隆MyObj对象,您可能希望新克隆引用与原始实例相同的Owner实例,但要制作NameTag的深层副本(当然,这只是使用虚构类的示例)。这将表示MyObj和NameTag实例之间的一对一关系,以及Owner和MyObj实例之间的一对多关系。以下代码考虑了您的问题中提到的两种情况:

class MyObj implements Cloneable {

    private Person owner;
    private NameTag tag;
    private int size; 

    public MyObj(Person owner, NameTag tag, int size) {
         this.owner = owner;
         this.tag = tag;
         this.size = size;
    }

    public Object clone() {

        MyObj result;

        //call all super clone() methods before doing class specific work
        //this ensures that no matter where you are in the inheritance heirarchy,
        //a deep copy is made at each level.
        try {
            result = (MyObj) super.clone();
        }
        catch (CloneNotSupportedException e) {
            throw new RuntimeException
            ("Super class doesn't implement cloneable");
        }

        //work specific to the MyObj class
        result.owner = owner;     //We want the reference to the Person, not a clone
        result.tag = tag.clone()  //We want a deep copy of the NameTag
        result.size = size;       //ints are primitive, so this is a copy operation    

        return result;
}

答案 3 :(得分:1)

一个例子是防御性复制参数(有效Java项目39:在需要时制作防御性副本)

class X {
  private byte[] a;

  X(byte[] a) {
      this.a = a.clone();
  }
...