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

发布于 2024-12-07 02:18:57 字数 1011 浏览 0 评论 0原文

我不明白克隆自定义对象的机制。例如:

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;
    }
}

这个例子展示了书中所写的正确的克隆方法。但我可以删除类名定义中的 Implements Cloneable,并且收到相同的结果。

所以我不明白Cloneable的提议以及为什么clone()方法被定义在类Object中?

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.

So I don't understand the proposing of Cloneable and why clone() method is defined in class Object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

您的好友蓝忘机已上羡 2024-12-14 02:18:57

克隆方法旨在进行深层复制。确保您了解深拷贝和浅拷贝之间的区别。在您的情况下,复制构造函数可能是您想要的模式。然而,在某些情况下,您不能使用此模式,例如,因为您正在子类化 X 类,并且您无权访问所需的 X 构造函数。如果 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;
    }

}

一般情况下,重写克隆方法时:

  • 使返回类型更加具体
  • 从调用 super.clone()
  • 当您知道 clone() 也适用于任何子类时,不要包含 throws 子句(克隆模式的弱点;如果可能,将类设为 Final)
  • 保留不可变和原始字段,但克隆可变对象调用后手动字段super.clone() (克隆模式的另一个弱点,因为这些字段无法最终确定)

Objectclone() 方法(当所有超类遵守契约时最终将被调用)创建浅拷贝并处理新对象的正确运行时类型。注意整个过程中没有调用构造函数。

如果您希望能够在实例上调用 clone(),请实现 Cloneable 接口并将该方法公开。如果您不想在实例上调用它,但确实希望确保子类可以调用它们的 super.clone() 并获取它们所需的内容,那么就不要实现 < code>Cloneable 并保持该方法protected(如果您的超类尚未将其声明为 public)。

克隆模式很困难并且有很多陷阱。确保这是您所需要的。考虑复制构造函数或静态工厂方法。

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. If X overrides its clone method correctly (if necessary) then you could make a copy in the following way:

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()
  • 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)
  • 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)

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. 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. 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.

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.

攀登最高峰 2024-12-14 02:18:57

JVM 能够为您克隆对象,因此您不应该自己构造一个新对象。只需使用以下代码:

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

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

即使 Person 类是子类化的,这也会起作用,而您的克隆实现将始终创建 Person 的实例(例如,而不是为 Employee 创建 Employee 的实例)。

The JVM is able to clone the object for you, and you're thus not supposed to construct a new person by yourself. 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).

风情万种。 2024-12-14 02:18:57

Object 类中的 clone() 对内存进行浅表复制,而不是调用构造函数等方法。为了在任何本身没有实现 clone() 的对象上调用 clone(),您需要实现 Clonable 接口。

如果您重写 clone() 方法,则不必实现该接口。

正如 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()

如果示例中的 A 将实现 Clonable 调用 clone()A >Object 版本)将生成一个新的 A 实例,该实例引用完全相同 StringBuilder,即对克隆中的 sb 进行更改实例将导致 sb 中的更改原始 A 实例。

这意味着浅拷贝,这也是为什么通常最好重写 clone() 的原因之一。

编辑:作为旁注,使用返回类型协方差将使您的重写 clone() 更加明确:

public Person clone() {
  ...
}

The clone() in class Object does a shallow copy of the memory instead of calling methods like the constructor. In order to call clone() on any object that doesn't implement clone() itself, you need to implement the Clonable interface.

If you override the clone() method you don't have to implement that interface.

Just as the JavaDoc says, this would result in an exception:

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, i.e. changes to sb in the cloned instance would result in changes to the sb in the original A instance.

That's meant with a shallow copy and that one reason why it is generally better to override clone().

Edit: just as a sidenote, using return type covariance would make your overridden clone() more explicit:

public Person clone() {
  ...
}
手长情犹 2024-12-14 02:18:57

克隆并不成熟,正如 Joshua bloch 所说:

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

clone is not mature as Joshua bloch say:

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

╰つ倒转 2024-12-14 02:18:57

无需在 clone() 方法中显式创建对象。只需调用 super.clone() 即可创建该对象的副本。它将执行浅克隆。

There's no need to create the object explicitly here in clone() method. Just by calling super.clone() will create the copy of this object. It will perform the shallow clone.

找回味觉 2024-12-14 02:18:57

它的目的与任何此类接口相同。首先,它允许方法(等)接受任何 Clonable 对象并可以访问它们所需的方法,而无需将自己限制为一个特定对象。诚然,Clonable 可能是这方面不太有用的接口之一,但肯定有一些地方您可能需要它。如果您想要更多想法,请考虑接口 Comparable,例如,它允许您对列表进行排序(因为列表不需要知道对象是什么,只需知道它们可以进行比较)。

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. Admittedly Clonable is probably one of the less useful interfaces in this respect, but there's certainly places where you might want it. 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).

灼痛 2024-12-14 02:18:57

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

if you dont declare cloneable interface you should be getting CloneNotSupportException when you call clone method.If you declare and then call clone method it will make shallow copy.

装迷糊 2024-12-14 02:18:57

在您的示例中,您没有进行实际的克隆。您被覆盖了对象类的clone()方法并给出了您自己的实现。但在您的克隆方法中,您正在创建一个新的 Person 对象。并返回它。所以在这种情况下,实际对象没有被克隆。

所以你的克隆方法应该是这样的:

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

所以这里克隆将由超类方法处理。

In your example you are not doing actual cloning.you are overridden the clone() method of object class and given your own implementation. but in your clone method you are creating a new Person object. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文