据我所知,Java中的clone()
方法可以让我们复制对象(而非引用)。但是我也读到过,这个复制是浅复制。那么有什么意义呢?clone()
方法给我的能力是什么,简单的赋值操作没有的呢?
据我所知,Java中的clone()
方法可以让我们复制对象(而非引用)。但是我也读到过,这个复制是浅复制。那么有什么意义呢?clone()
方法给我的能力是什么,简单的赋值操作没有的呢?
区别在于您可以修改克隆的对象而不修改原始对象。
Point p = new Point(1,2);
Point p2 = p.clone();
Point p3 = p;
p2.x = 5;
p3.y = 7;
在 p3
上的修改会反馈到 p
,而在 p2
上的修改则不会。
让我们看看单个语句执行后的情况(假设 1
、2
、5
、7
是对象):
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 |
'-----'
一个赋值操作会将一个实例的引用复制到一个变量中。一个克隆操作会克隆实例(并将引用分配给克隆体)。
使用赋值操作,你最终会得到指向一个对象的多个变量,而使用克隆操作,你会有多个变量,它们持有多个对象的引用。
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
简单的赋值只会为对象创建一个别名。使用clone()方法,每个属性成员也将在克隆对象中初始化。然而,如果属性成员本身包含更多的对象,则这些对象不会被复制。
浅复制是Object的默认行为,您可以重写clone方法以执行深度复制。
要深度克隆,您必须实现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);
}
}
x
和y
指向的对象。即使p.x
和p2.x
的值相同(指向同一个对象),它们仍然是不同的变量,对其中一个进行赋值并不会改变另一个。在这种情况下,它们甚至不是对象,而是原始值,但如果它们是对象,同样的规则也适用。 - Paŭlo Ebermann1
的“值”为其他内容,那么所有使用此数字的对象都会显示该变化。但是数字(即int,在假设为java.awt.Point或类似物体中)是不可变的 - 你可以通过赋值更改变量的内容,但不能更改1的值(否则编写可靠程序将变得非常复杂)。 - Paŭlo Ebermann