浅拷贝和深拷贝的定义
浅拷贝:只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制。
深拷贝:对象,对象内部的引用均复制。
为什么需要有对象拷贝?
有时候我们要获取到一个当前状态的对象复制品,他们是两个独立对象。不再是引用或者引用拷贝(实质都是指向对象本身)。就是说a是b的拷贝,b发生变化的时候,不要影响a。
对象拷贝有浅拷贝和深度拷贝两种
浅拷贝
浅拷贝是指对象中基本数据类型得到拷贝,而引用数据类型并未拷贝。
提到拷贝自然和clone联系起来了,所有具有clone功能的类都有一个特性,那就是它直接或间接地实现了Cloneable接口。
否则,我们在尝试调用clone()方法时,将会触发CloneNotSupportedException异常。
eg:class DOG implements Cloneable {
public DOG(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
public String name;
private int age;
// test
public static void main(String[] args) {
DOG dog1 = new DOG(" xiaogou ", 2);
DOG dog2 = (DOG) dog1.clone();
dog1.name = " dagou ";
System.out.println(dog2.getName());
System.out.println(dog2.getAge());
System.out.println(dog1.getName());
System.out.println(dog1.getAge());
}
}
深度拷贝
相对浅拷贝。实现对象中基本数据类型和引用数据类型的拷贝
class AAA { public AAA(String name) { this.name = name; } public String name; } class DOG implements Cloneable { public DOG(String name, int age, AAA birthday) { this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public int getAge() { return age; } public AAA getBirthday() { return birthday; } public String getBirth(AAA a) { return a.name; } public String name; private int age; public AAA birthday; public Object clone() { try { super.clone(); return super.clone(); } catch (Exception e) { return null; } } } public class TestClone { public static void main(String[] args) { AAA Day = new AAA(" test "); DOG dog1 = new DOG(" xiaogou ", 2, Day); DOG dog2 = (DOG) dog1.clone(); // dog2.birthday = (AAA) dog1.birthday.clone(); dog1.birthday.name = " 333 "; System.out.println(dog1.getBirth(dog1.birthday)); System.out.println(dog2.getBirth(dog2.birthday)); } } |
// 运行结果是:
// 333
// 333
// 而真正要实现拷贝还的加点代码,如下请对比上面和下面代码的异同之处
class AAA implements Cloneable{ public Object clone() dog1.birthday.name = " 333 "; 运行结果: |
但是明显的这种方法还是有许多不足,人们总是希望一个clone就是对象直接克隆。而上面还要对对象中的对象递归使用clone。下面提供一种更高级点的做法
序列化
class AAA implements Serializable {
public AAA(String name) {
this.name = name;
}
public String name;
}
class DOG extends SerialCloneable {
public DOG(String name, int age, AAA birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public AAA getBirthday() {
return birthday;
}
public String getBirth(AAA a) {
return a.name;
}
public String name;
private int age;
public AAA birthday;
public Object clone() {
try {
super.clone();
return super.clone();
} catch (Exception e) {
return null;
}
}
}
class TestClone {
public static void main(String[] args) {
AAA Day = new AAA(" test ");
DOG dog1 = new DOG(" xiaogou ", 2, Day);
DOG dog2 = (DOG) dog1.clone();
// dog2.birthday = (AAA) dog1.birthday.clone();
dog1.birthday.name = " 333 ";
System.out.println(dog1.getBirth(dog1.birthday));
System.out.println(dog2.getBirth(dog2.birthday));
}
}
class SerialCloneable implements Cloneable, Serializable {
public Object clone() {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(this);
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout
.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = in.readObject();
in.close();
return ret;
} catch (Exception e) {
return null;
}
}
}
// 输出:
// 333
// test
//这样也能够实现