关于clone() 浅拷贝 和深拷贝 通过例子分析
结论:
浅拷贝:
Object的clone() 会返回一个与原对象不同的引用
,但是是浅拷贝,即拷贝后的成员与原对象的成员是引用的相同的地址
,即整个对象引用不同,成员引用相同
如下图:浅拷贝对象有不同的散列值,但是成员数组引用相同,修改其中一个,另一个也相应改变
深拷贝
对于自定义类型,在实现Cloneable接口的基础上,可以重写clone()函数,这里可以手动对成员引用指向不同的值,这样,就实现了深拷贝
以下代码在去掉注释后的运行结果:
class DeepCloneExample implements Cloneable {
private int[] arr;
public DeepCloneExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
}
public void set(int index, int value) {
arr[index] = value;
}
public int get(int index) {
return arr[index];
}
@Override
protected DeepCloneExample clone() throws CloneNotSupportedException {
DeepCloneExample result = (DeepCloneExample) super.clone();
// result.arr = new int[arr.length];
// for (int i = 0; i < arr.length; i++) {
// result.arr[i] = arr[i];
// }
return result;
}
}
clone() 的替代方案
使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。
public class CloneConstructorExample {
private int[] arr;
public CloneConstructorExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
}
public CloneConstructorExample(CloneConstructorExample original) {
arr = new int[original.arr.length];
for (int i = 0; i < original.arr.length; i++) {
arr[i] = original.arr[i];
}
}
public void set(int index, int value) {
arr[index] = value;
}
public int get(int index) {
return arr[index];
}
}
DeepCloneExample e1 = new DeepCloneExample();
DeepCloneExample e2 = null;
try {
e2 = e1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
e1.set(2, 222);
System.out.println(e2.get(2)); // 2