什么是浅克隆与深克隆
简单点说浅克隆是一个不完善的克隆,内部分成员没有完成克隆复制,从而造成克隆者与被克隆对象的数据没有完全分离产生数据交叉混乱的问题。深克隆就是解决浅克隆的问题。
为什么会出现浅克隆问题
之所以出现浅克隆的问题,其根本原因是Java中引用类型和基本类型的赋值操作不同。
引用类型和基本类型的赋值操作
// 基本类型
int a = 10;
int b = a;//b=20
b = 20;//b=20,a=10
// 引用类型
Student aStu=new Student("张三");//aStu.name="张三"
Student bStu=aStu;//bStu.name="张三",aStu.name="张三"
bStu.name="李四";//bStu.name="李四",aStu.name="李四"
产生如此结果的原因是:
变量a和变量b都有自己的空间,修改b当然不会影响到a,但是在引用赋值时不会将其内容复制一遍,仅仅将其地址进行复制,因此两个引用实际指向的是相同的空间,就会出现修改bStu成员会影响到aStu的成员的现象,这显然不是我们想看到的结果。
浅克隆与深克隆进一步分析
浅克隆就是只用赋值进行数据克隆,此种克隆方法在克隆基本类型的成员时没用问题,但是在克隆引用类型的成员时就会出现上述问题。
深克隆就是解决浅克隆问题,其特点是在克隆引用类型的成员时不使用简单赋值方法,而是先将引用的数据复制一份再赋值。
代码实例
浅克隆
public class DeepAShallowClone {
public static void main(String[] args) throws CloneNotSupportedException {
Student aStu = new Student(11,"张三",new Address("北京","王家小区"));
Student bStu = (Student) aStu.clone();
bStu.setAge(12);
bStu.setName("李四");
bStu.getAdr().setCity("深圳");
System.out.println(aStu);
System.out.println("aStu Name hashCode:" + aStu.getName().hashCode());
System.out.println("aStu Address hashCode:" + aStu.getAdr().hashCode());
System.out.println(bStu);
System.out.println("bStu Name hashCode:" + bStu.getName().hashCode());
System.out.println("bStu Address hashCode:" + bStu.getAdr().hashCode());
}
}
class Student implements Cloneable{
private int age;
private String name;
private Address adr;
public Student(int age, String name, Address adr) {
this.age = age;
this.name = name;
this.adr = adr;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAdr() {
return adr;
}
public void setAdr(Address adr) {
this.adr = adr;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", adr=" + adr +
'}';
}
}
class Address implements Cloneable {
String City;
String Community;
public Address(String city, String community) {
City = city;
Community = community;
}
public void setCity(String city) {
City = city;
}
@Override
public String toString() {
return "Address{" +
"City='" + City + '\'' +
", Community='" + Community + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("adr clone");
return super.clone();
}
}
执行结果
Student{age=11, name='张三', adr=Address{City='深圳', Community='王家小区'}}
aStu Name hashCode:774889
aStu Address hashCode:610998173
Student{age=12, name='李四', adr=Address{City='深圳', Community='王家小区'}}
bStu Name hashCode:842061
bStu Address hashCode:610998173
super.clone()方法只进行简单的赋值操作,结果中能看到两个对象的Address成员的地址是相同的(哈希值一定程度上可以当做地址看待),可以得出结论两个Address成员在内存中其实是一个实例,因此在bStu在更改其Address的内容时会影响到aStu。
深克隆
public class DeepAShallowClone {
public static void main(String[] args) throws CloneNotSupportedException {
Student aStu = new Student(11,"张三",new Address("北京","王家小区"));
Student bStu = (Student) aStu.clone();
bStu.setAge(12);
bStu.setName("李四");
bStu.getAdr().setCity("深圳");
System.out.println(aStu);
System.out.println("aStu Name hashCode:" + aStu.getName().hashCode());
System.out.println("aStu Address hashCode:" + aStu.getAdr().hashCode());
System.out.println(bStu);
System.out.println("bStu Name hashCode:" + bStu.getName().hashCode());
System.out.println("bStu Address hashCode:" + bStu.getAdr().hashCode());
}
}
class Student implements Cloneable{
private int age;
private String name;
private Address adr;
public Student(int age, String name, Address adr) {
this.age = age;
this.name = name;
this.adr = adr;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAdr() {
return adr;
}
public void setAdr(Address adr) {
this.adr = adr;
}
@Override
public Object clone() throws CloneNotSupportedException {
Student adr=(Student)super.clone();
adr.adr=(Address)this.adr.clone();
return adr;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", adr=" + adr +
'}';
}
}
class Address implements Cloneable {
String City;
String Community;
public Address(String city, String community) {
City = city;
Community = community;
}
public void setCity(String city) {
City = city;
}
@Override
public String toString() {
return "Address{" +
"City='" + City + '\'' +
", Community='" + Community + '\'' +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
System.out.println("adr clone");
return super.clone();
}
}
执行结果
Student{age=11, name='张三', adr=Address{City='北京', Community='王家小区'}}
aStu Name hashCode:774889
aStu Address hashCode:610998173
Student{age=12, name='李四', adr=Address{City='深圳', Community='王家小区'}}
bStu Name hashCode:842061
bStu Address hashCode:2047329716
在结果中可以看出两个对象的Address成员的地址是不同,二者就不会相互影响了。