对象类具有一个clone方法,如果实例变量为基本类型,则可使用该方法复制对象的值而不会产生任何副作用。但是在实例变量作为对象的情况下,由于仅复制了引用,因此副作用起着作用。可以通过重写克隆方法来解决此问题。请参见以下示例。
public class Tester { public static void main(String[] args) throws CloneNotSupportedException { //方案1:浅拷贝 B b1 = new B(); A a1 = new A(); a1.a = 1; a1.b = 2; b1.aObject = a1; b1.a = 1; //打印一个a1对象 printObject(b1.aObject, "b1.a", b1.a); //克隆运算符复制参考 B b2 = b1.clone(); //b1.aObject.a和b2.aObject.a现在指向同一对象 //修改b2.aObject.a,更改将反映在b1.aObject.a- b2.aObject.a = 3; printObject(b1.aObject, "b1.a", b1.a); printObject(b2.aObject, "b2.a", b2.a); //方案2:使用深度复制 C c1 = new C(); A a3 = new A(); a3.a = 1; a3.b = 2; c1.aObject = a3; c1.a = 1; //打印一个a1对象 printObject(c1.aObject, "c1.a", c1.a); C c2 = c1.clone(); //c1.aObject.a和c2.aObject.a现在指向不同的对象 //修改c2.aObject.a,更改不会反映在c1.aObject.a- c2.aObject.a = 3; printObject(c1.aObject, "c1.a", c1.a); printObject(c2.aObject, "c2.a", c2.a); } private static void printObject(A a, String name, int value) { System.out.println(name + ": [" + a.a + ", " + a.b + "]" + ", " + value); } } class A { public int a; public int b; } class B implements Cloneable { public int a; public A aObject; public B clone() throws CloneNotSupportedException { B b = (B)super.clone(); return b; } } class C implements Cloneable { public int a; public A aObject; public C clone() throws CloneNotSupportedException { C c = (C)super.clone(); c.aObject = new A(); c.aObject.a = this.aObject.a; c.aObject.b = this.aObject.b; return c; } }
输出结果
b1.a: [1, 2], 1 b1.a: [3, 2], 1 b2.a: [3, 2], 1 c1.a: [1, 2], 1 c1.a: [1, 2], 1 c2.a: [3, 2], 1
在原始实例变量的情况下,clone()方法没有副作用,因为在克隆过程中会创建一个新对象。
如果将对象作为实例变量使用,则clone()方法(如果未正确实施)也会产生副作用,因为克隆的对象具有引用的副本。这被称为浅表副本。
可以重写clone()方法,以防止可以单独创建实例变量对象的浅表复制,并且可以更新其属性。这被称为深层副本。