Java中的clone()方法

9

据我所知,Java中的clone()方法可以让我们复制对象(而非引用)。但是我也读到过,这个复制是浅复制。那么有什么意义呢?clone()方法给我的能力是什么,简单的赋值操作没有的呢?

5个回答

23

区别在于您可以修改克隆的对象而不修改原始对象。

Point p = new Point(1,2);
Point p2 = p.clone();
Point p3 = p;
p2.x = 5;
p3.y = 7;

p3 上的修改会反馈到 p,而在 p2 上的修改则不会。

让我们看看单个语句执行后的情况(假设 1257 是对象):

Point p = new Point(1,2);

            .-----.    .-----.
 p  ----->  |  x -+--> |  1  |
            |     |    '-----'
            |     |    .-----.
            |  y -+--> |  2  |
            '-----'    '-----'


Point p2 = p.clone();

            .-----.    .-----.    .-----.
 p  ----->  |  x -+--> |  1  | <--+- x  |  <----- p2
            |     |    '-----'    |     |
            |     |    .-----.    |     |
            |  y -+--> |  2  | <--+- y  |
            '-----'    '-----'    '-----'

Point p3 = p;

            .-----.    .-----.    .-----.
 p  ----->  |  x -+--> |  1  | <--+- x  |  <----- p2
            |     |    '-----'    |     |
            |     |    .-----.    |     |
 p3 ----->  |  y -+--> |  2  | <--+- y  |
            '-----'    '-----'    '-----'


p2.x = 5;

            .-----.    .-----.    .-----.    .-----.
 p  ----->  |  x -+--> |  1  |    |  x -+--> |  5  |
            |     |    '-----'    |     |    '-----'
            |     |    .-----.    |     |
 p3 ----->  |  y -+--> |  2  | <--+- y  |  <----- p2
            '-----'    '-----'    '-----'


p3.y = 7;

            .-----.    .-----.    .-----.    .-----.
 p  ----->  |  x -+--> |  1  |    |  x -+--> |  5  |
            |     |    '-----'    |     |    '-----'
            |     |    .-----.    |     |
 p3 ----->  |  y  |    |  2  | <--+- y  |  <----- p2
            '--+--'    '-----'    '-----'
               |     .-----.
               '---> |  7  |
                     '-----'

谢谢,但我不明白为什么p2.x不会改变p中的任何内容。虽然我们有两个不同的对象,但它们指向相同的x和y(因为浅拷贝)。我错过了什么吗? - Tom
最后两行的赋值语句改变了 xy 指向的对象。即使 p.xp2.x 的值相同(指向同一个对象),它们仍然是不同的变量,对其中一个进行赋值并不会改变另一个。在这种情况下,它们甚至不是对象,而是原始值,但如果它们是对象,同样的规则也适用。 - Paŭlo Ebermann
1
在这个例子中,我们看不到浅克隆和深克隆之间的区别。 - Paŭlo Ebermann
@PaŭloEbermann 如果 clone() 确实只进行浅拷贝,那么对其中一个对象的更改会反映在另一个对象上吗?我有点困惑。 - Inquisitive
@Subhra: 如果你想改变数字1的“值”为其他内容,那么所有使用此数字的对象都会显示该变化。但是数字(即int,在假设为java.awt.Point或类似物体中)是不可变的 - 你可以通过赋值更改变量的内容,但不能更改1的值(否则编写可靠程序将变得非常复杂)。 - Paŭlo Ebermann

7

一个赋值操作会将一个实例的引用复制到一个变量中。一个克隆操作会克隆实例(并将引用分配给克隆体)。

使用赋值操作,你最终会得到指向一个对象的多个变量,而使用克隆操作,你会有多个变量,它们持有多个对象的引用。

SomeCloneable a = new SomeCloneable();
SomeCloneable b = a;                     // a and b point to the same object

/* versus */

SomeCloneable a = new SomeCloneable();
SomeCloneable b = a.clone();             // a and b point to the different objects

4

简单的赋值只会为对象创建一个别名。使用clone()方法,每个属性成员也将在克隆对象中初始化。然而,如果属性成员本身包含更多的对象,则这些对象不会被复制。


3

浅复制是Object的默认行为,您可以重写clone方法以执行深度复制。


1

要深度克隆,您必须实现Cloneable并覆盖clone()方法。

public class MyClass implements Cloneable {

private Object attr = new Object();

@Override
public Object clone() throws CloneNotSupportedException {
    MyClass clone = (MyClass)super.clone();
    clone.attr = new Object();
    return clone;
}

@Override
public String toString() {
    return super.toString()+", attr=" + attr;
}

public static void main(String[] args) throws Exception {
    MyClass x = new MyClass();
    System.out.println("X="+x);
    MyClass y = (MyClass)x.clone();
    System.out.println("Y="+y);
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接