Java支持我们对一个对象进行克隆,通常用在装饰模式和原型模式中,克隆分为两种:
浅克隆:通常只是对克隆的实例进行复制,如果被克隆的实例的变量是原始数据类型和不可改变类,则克隆和被克隆实例的变量是不共用的;如果被克隆的实例的变量是可变引用数据类型,则克隆和被克隆实例的变量是引用同一个对象的,改变其中一个实例的变量的属性值会影响到另外一个实例的变量的属性值。
深克隆:和浅克隆的差别在于,可变引用数据类型也是不共用的。
浅克隆,实现Cloneable,并重写clone方法
public class Demo {
public static void main(String[] args) {
A a=new A();
a.i=10;
B b=new B();
b.j=20;
b.s="s";
b.k=new Integer(30);
b.a=a;
try {
B bClone=(B)b.clone();
bClone.j=40;
bClone.s="ss";
bClone.k=50;
bClone.a.i = 60;
System.out.println(b.j);// 结果:20 。原因:原始数据类型,不会互相影响。
System.out.println(b.s);// 结果:s。原因:不可变引用数据类型,不会互相影响。
System.out.println(b.k);// 结果:30。原因:不可变引用数据类型,不会互相影响。
System.out.println(b.a.i);// 结果:60。原因:可变引用数据类型是共用的。
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
class A {
int i;
}
class B implements Cloneable{
int j;
String s;
Integer k;
A a;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
深克隆,利用对象流
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Demo {
public static void main(String[] args) {
A a = new A();
a.i = 10;
B b = new B();
b.a = a;
try {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(baos);
oos.writeObject(b);
ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bais);
B b1=(B)ois.readObject();
b1.a.i=20;
System.out.println(b.a.i);// 结果:10。原因:可变引用数据类型不共用的。
oos.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@SuppressWarnings("serial")
class A implements Serializable{
int i;
}
@SuppressWarnings("serial")
class B implements Serializable {
A a;
}