【发布时间】:2011-06-17 11:04:40
【问题描述】:
据我了解,clone() 方法使我们能够在 Java 中复制对象(无引用)。但我也读到,副本很浅。那么有什么意义呢? clone() 方法给了我哪些能力,而简单的评估却没有?
【问题讨论】:
标签: java
据我了解,clone() 方法使我们能够在 Java 中复制对象(无引用)。但我也读到,副本很浅。那么有什么意义呢? clone() 方法给了我哪些能力,而简单的评估却没有?
【问题讨论】:
标签: java
不同的是,你可以修改克隆的对象而不修改原始对象。
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 |
'-----'
【讨论】:
x 和 y 指向的内容。即使p.x 和p2.x 具有相同的值(指的是同一个对象),它们也是不同的变量,赋值给一个不会改变另一个。 (在这种情况下,它们甚至不是对象,而是原始值,但如果它们是对象,同样的事情也是有效的。)
1 的“值”更改为其他值,这将显示在使用此数字的所有对象中。但是数字(即这里的整数,假设 java.awt.Point 或类似的东西)是不可变的 - 您可以更改变量的内容(每个赋值),但不能更改 1 的值(否则编写可靠的程序会非常复杂)。
赋值将实例的引用复制到变量。 clone 操作将克隆实例(并为克隆分配一个引用)。
使用 assignment,您将得到 多个 变量指向 一个 对象,通过克隆,您将拥有 多个 持有多个对象引用的变量。
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
【讨论】:
Cloneable 不会公开 clone() 方法。您必须将您的a 和b 声明为SomeCloneable。
一个简单的分配将简单地为对象创建一个别名。使用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);
}
}
【讨论】: