简体   繁体   English

如何使用clone()方法克隆Java对象

[英]How to clone a Java object with the clone() method

I don't understand the mechanism of cloning custom object. 我不明白克隆自定义对象的机制。 For example: 例如:

public class Main{

    public static void main(String [] args) {

        Person person = new Person();
        person.setFname("Bill");
        person.setLname("Hook");

        Person cloned = (Person)person.clone();
        System.out.println(cloned.getFname() + " " + cloned.getLname());
    }
}

class Person implements Cloneable{

    private String fname;
    private String lname;

    public Object clone() {

        Person person = new Person();
        person.setFname(this.fname);
        person.setLname(this.lname);
        return person;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public void setLname(String lname){
        this.lname = lname;
    }

    public String getFname(){
        return fname;
    }

    public String getLname() {
        return lname;
    }
}

This is example shows right way of cloning as a in the books write. 这个示例显示了正确的克隆方式,如书中所写。 But I can delete implements Cloneable in the class name definition and I receive the same result. 但是我可以在类名定义中删除implements Cloneable,并且我收到相同的结果。

So I don't understand the proposing of Cloneable and why clone() method is defined in class Object? 所以我不明白Cloneable的提议以及为什么在类Object中定义了clone()方法?

The clone method is meant to make a deep copy. 克隆方法旨在进行深层复制。 Make sure you understand the difference between deep and shallow copies. 确保您了解深拷贝和浅拷贝之间的区别。 In your case a copy constructor may be the pattern you want. 在您的情况下,复制构造函数可能是您想要的模式。 In some cases you can't use this pattern however, for example because you're subclassing class X and you don't have access to the constructor of X that you need. 在某些情况下,您无法使用此模式,例如,因为您正在为类X创建子类,并且您无法访问所需的X构造函数。 If X overrides its clone method correctly (if necessary) then you could make a copy in the following way: 如果X正确覆盖其克隆方法(如有必要),则可以按以下方式复制:

class Y extends X implements Cloneable {

    private SomeType field;    // a field that needs copying in order to get a deep copy of a Y object

    ...

    @Override
    public Y clone() {
        final Y clone;
        try {
            clone = (Y) super.clone();
        }
        catch (CloneNotSupportedException ex) {
            throw new RuntimeException("superclass messed up", ex);
        }
        clone.field = this.field.clone();
        return clone;
    }

}

In general when overriding your clone method: 通常在覆盖克隆方法时:

  • Make the return type more specific 使返回类型更具体
  • Start with calling super.clone() 从调用super.clone()
  • Do not include throws clause when you know clone() will also work for any subclass (weakness of the clone-pattern; make class final if possible) 当你知道clone()也适用于任何子类时(克隆模式的弱点;如果可能的话,make class final),不要包含throws子句
  • Leave immutable and primitive fields alone, but clone mutable object fields manually after the call to super.clone() (another weakness of the clone-pattern, since these fields cannot be made final) 保留不可变和原始字段,但在调用super.clone()之后手动克隆可变对象字段(克隆模式的另一个弱点,因为这些字段不能成为最终字段)

The clone() method of Object (which will eventually be called when all superclasses obey the contract) makes a shallow copy and takes care of the correct runtime type of the new object. Objectclone()方法(最终将在所有超类遵循契约时调用)生成浅层副本并处理新对象的正确运行时类型。 Note how no constructor is called in the entire process. 请注意在整个过程中如何调用构造函数。

If you want to be able to call clone() on instances, then implement the Cloneable interface and make the method public. 如果您希望能够在实例上调用clone() ,则实现Cloneable接口并将该方法设为public。 If you don't want to be able to call it on instances, but you do want to make sure subclasses can call their super.clone() and get what they need, then don't implement Cloneable and keep the method protected if your superclass hasn't declared it public already. 如果您不希望能够在实例上调用它,但您确实希望确保子类可以调用它们的super.clone()并获得它们所需的内容,那么请不要实现Cloneable并保持方法protected超类还没有宣布它是公开的。

The clone pattern is difficult and has a lot of pitfalls. 克隆模式很难并且有很多陷阱。 Be sure it's what you need. 确保它是你需要的。 Consider copy constructors, or a static factory method. 考虑复制构造函数或静态工厂方法。

The clone() in class Object does a shallow copy of the memory instead of calling methods like the constructor. Object类中的clone()执行内存的浅表副本,而不是像构造函数那样调用方法。 In order to call clone() on any object that doesn't implement clone() itself, you need to implement the Clonable interface. 为了在任何不实现clone()本身的对象上调用clone() ,您需要实现Clonable接口。

If you override the clone() method you don't have to implement that interface. 如果重写clone()方法,则不必实现该接口。

Just as the JavaDoc says, this would result in an exception: 正如JavaDoc所说,这将导致异常:

class A {
  private StringBuilder sb; //just some arbitrary member
}

...

new A().clone(); //this will result in an exception, since A does neither implement Clonable nor override clone()

If A in the example would implement Clonable calling clone() (the Object version) would result in a new A instance that references the very same StringBuilder, ie changes to sb in the cloned instance would result in changes to the sb in the original A instance. 如果A在例如将实现Clonable调用clone()Object版本)将导致新的A引用同样的 StringBuilder实例,即改变sb在克隆的情况下会导致更改sb在原A实例。

That's meant with a shallow copy and that one reason why it is generally better to override clone() . 这意味着一个浅拷贝,这是为什么通常更好地覆盖clone()一个原因。

Edit: just as a sidenote, using return type covariance would make your overridden clone() more explicit: 编辑:正如旁注,使用返回类型协方差将使您的重写clone()更明确:

public Person clone() {
  ...
}

The JVM is able to clone the object for you, and you're thus not supposed to construct a new person by yourself. JVM能够为您克隆对象,因此您不应该自己构建新人。 Just use this code: 只需使用此代码:

class Person implements Cloneable {
    // ...
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

or 要么

class Person implements Cloneable {
    // ...
    @Override
    public Object clone() {
        try {
            return super.clone();
        }
        catch (CloneNotSupportedException e) {
            throw new Error("Something impossible just happened");
        }
    }
}

This will work even if the Person class is subclassed, whereas your clone implementation will always create an instance of Person (and not an instance of Employee for an Employee, for example). 即使Person类是子类,这也会起作用,而您的克隆实现将始终创建Person的实例(例如,不是Employee的Employee实例)。

clone is not mature as Joshua bloch say: 克里斯并不成熟,约书亚布洛赫说:

http://www.artima.com/intv/bloch13.html http://www.artima.com/intv/bloch13.html

There's no need to create the object explicitly here in clone() method. 这里没有必要在clone()方法中显式创建对象。 Just by calling super.clone() will create the copy of this object. 只需调用super.clone()创建此对象的副本。 It will perform the shallow clone. 它将执行浅层克隆。

It's the same purpose as any such interface. 它与任何此类界面的目的相同。 Primarily it allows methods (etc.) to accept ANY Clonable object and have access to the method they need without limiting themselves to one specific object. 它主要允许方法(等)接受任何Clonable对象,并且可以访问他们需要的方法,而不必将自己限制在一个特定的对象上。 Admittedly Clonable is probably one of the less useful interfaces in this respect, but there's certainly places where you might want it. 诚然,Clonable可能是这方面不太有用的接口之一,但肯定有你可能需要它的地方。 If you want more of an idea consider the interface Comparable which for example allows you to have sorted lists (because the list doesn't need to know what the object is, only that they can be compared). 如果你想要更多的想法,可以考虑接口Comparable,例如允许你有排序列表(因为列表不需要知道对象是什么,只是可以比较它们)。

如果你没有声明克隆接口,那么在调用clone方法时你应该得到CloneNotSupportException。如果你声明然后调用clone方法,它将进行浅拷贝。

In your example you are not doing actual cloning.you are overridden the clone() method of object class and given your own implementation. 在您的示例中,您没有进行实际克隆。您将覆盖对象类的clone()方法并给出您自己的实现。 but in your clone method you are creating a new Person object. 但是在你的克隆方法中,你正在创建一个新的Person对象。 and returning it.So in this case the actual object is not cloned. 并返回它。在这种情况下,实际对象不会被克隆。

So your clone method should be like : 所以你的克隆方法应该是这样的:

public Object clone() {
      return super.clone();
  }

So here clone will be handled by superclass method. 所以这里克隆将由超类方法处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM