今天的记录是java的克隆机制以及深克隆和浅克隆,话不多说,线上代码:
public static class Boss{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public static class Boy implements Cloneable{
private Boss boss;
private int number;
private List<Integer> list=new ArrayList<>();
public Boy(){
boss=new Boss();
}
public Boss getBoss() {
return boss;
}
public void setBoss(Boss boss) {
this.boss = boss;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public String toString() {
return super.toString();
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
我们这里的boy是指小弟,boss是老板,于是小弟会对应一个老板,但是老板没有实现克隆而只有小弟实现了克隆,测试一下会有什么样的结果呢?
public static void main(String[] args) throws Exception{
Boy boy1=new Boy();
boy1.boss.setNumber(0);
boy1.setNumber(0);
Boy boy2=(Boy) boy1.clone();
boy2.boss.setNumber(1);
boy2.setNumber(1);
System.out.println(boy1.boss.number);
System.out.println(boy2.boss.number);
System.out.println(boy1.number);
System.out.println(boy2.number);
}
输出结果:
boy1 number 1
boy2 number 1
boy1 boss number 0
boy2 boss number 1
可以看到,boy.name是克隆了,但是boy.boss依然没有被克隆,其实这里的原因是java的克隆机制问题。直接调用java的克隆发生的都是浅克隆,即对于基本数据类型直接拷贝,而对于对象则拷贝对象的引用,因此要成功克隆boss,需要这么改:
public static class Boss implements Cloneable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static class Boy implements Cloneable{
private Boss boss;
private int number;
private List<Integer> list=new ArrayList<>();
public Boy(){
boss=new Boss();
}
public Boss getBoss() {
return boss;
}
public void setBoss(Boss boss) {
this.boss = boss;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public String toString() {
return super.toString();
}
@Override
public Object clone() throws CloneNotSupportedException {
Boy boy=(Boy) super.clone();
boy.boss=(Boss) this.boss.clone();
return boy;
}
}
再次运行:
boy1 number 0
boy2 number 1
boy1 boss number 0
boy2 boss number 1
事实上clone不是一种实现深克隆的好办法,真正实现深克隆的最好的办法是使用序列化与反序列化:
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) throws Exception{
Boy boy1=new Boy();
boy1.setNumber(0);
boy1.boss.setNumber(0);
Boy boy2=clone(boy1);
boy2.setNumber(1);
boy2.boss.setNumber(1);
System.out.println(boy1.boss.number);
System.out.println(boy2.boss.number);
System.out.println(boy1.number);
System.out.println(boy2.number);
}
public static class Boss implements Serializable{
private int number;
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public static class Boy implements Serializable{
private Boss boss;
private int number;
private List<Integer> list=new ArrayList<>();
public Boy(){
boss=new Boss();
}
public Boss getBoss() {
return boss;
}
public void setBoss(Boss boss) {
this.boss = boss;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
public static <T> T clone(T obj) throws Exception{
ByteArrayOutputStream bout=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bout);
oos.writeObject(obj);
ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bin);
return (T) ois.readObject();
}
}