浅克隆(ShallowClone)和深克隆(DeepClone)区别以及实现
什么是克隆克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。浅克隆和深克隆区别浅克隆: 被Clone的对象的所有变量都含有原来对象相同的值,而引用变量还是原来对用的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。】深克隆: 被克隆对象的所有变量都含有原来的对象相同的值,引用变量也重新复制了一份【不仅拷贝对象本身,而且拷贝对象包含的引用指...
什么是克隆
克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。
浅克隆和深克隆区别
- 浅克隆: 被Clone的对象的所有变量都含有原来对象相同的值,而引用变量还是原来对用的引用【拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。】
- 深克隆: 被克隆对象的所有变量都含有原来的对象相同的值,引用变量也重新复制了一份【不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象】
浅克隆demo
public class Student {
private Long id;
private String name;
private Integer sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex + "]";
}
}
public class Clazz implements Cloneable {
private Long number;
private String name;
private Student stu;
@Override
protected Clazz clone() throws CloneNotSupportedException {
Clazz cla = (Clazz)super.clone();
return cla;
}
public Long getNumber() {
return number;
}
public void setNumber(Long number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
@Override
public String toString() {
return "Clazz [number=" + number + ", name=" + name + ", stu=" + stu + "]";
}
}
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
test();
}
private static void test() throws CloneNotSupportedException {
Clazz cla = getClazz();
System.out.println("cla_1>:"+cla+"cla_1.hashCode>:"+cla.hashCode()+"-----cla_1_stu.hashCode>:"+cla.getStu().hashCode());
Clazz cla2 = cla.clone();
System.out.println("cla_2>:"+cla2+"cla_2.hashCode>:"+cla2.hashCode()+"-----cla_2_stu.hashCode>:"+cla2.getStu().hashCode());
cla2.setName("999体育班");
Student changeStu = cla2.getStu();
changeStu.setName("小王");
changeStu.setId(2L);
changeStu.setSex(1);
System.out.println("-----修改了Clone出来的Clazz.name以及Clazz.stu.name----------");
System.out.println("cla_1>:"+cla+"cla_1.hashCode>:"+cla.hashCode()+"-----cla_1_stu.hashCode>:"+cla.getStu().hashCode());
System.out.println("cla_2>:"+cla2+"cla_2.hashCode>:"+cla2.hashCode()+"-----cla_2_stu.hashCode>:"+cla2.getStu().hashCode());
}
private static Student getStudent() {
Student stu = new Student();
stu.setId(1L);
stu.setName("小李");
stu.setSex(0);
return stu;
}
private static Clazz getClazz() {
Clazz cla = new Clazz();
cla.setNumber(324L);
cla.setName("文化班");
cla.setStu(getStudent());
return cla;
}
}
- 打印结果:
由此可见,浅克隆,被克隆对象中的引用还是一样的,hashCode值也是一样的
深克隆demo
public class Student implements Cloneable{
private Long id;
private String name;
private Integer sex;
@Override
protected Student clone() throws CloneNotSupportedException {
return (Student)super.clone();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", sex=" + sex + "]";
}
}
public class Clazz implements Cloneable {
private Long number;
private String name;
private Student stu;
@Override
protected Clazz clone() throws CloneNotSupportedException {
Clazz cla = (Clazz)super.clone();
cla.stu = stu.clone(); // 引用对象也需要Clone
return cla;
}
public Long getNumber() {
return number;
}
public void setNumber(Long number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student getStu() {
return stu;
}
public void setStu(Student stu) {
this.stu = stu;
}
@Override
public String toString() {
return "Clazz [number=" + number + ", name=" + name + ", stu=" + stu + "]";
}
}
// 同样的CloneTest.java就不复制出来了
- 打印结果
浅克隆,被克隆对象中的引用(hashCode值)不一样,cla和cla2中的stu是两个不同的对象,不同的内存地址
附:
cloneable接口的作用
cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。Object中clone方法:
这里有一个疑问,Object中的clone方法是一个空的方法,那么他是如何判断类是否实现了cloneable接口呢?
原因在于这个方法中有一个native关键字修饰。
native修饰的方法都是空的方法,但是这些方法都是有实现体的(这里也就间接说明了native关键字不能与abstract同时使用。因为abstract修饰的方法与java的接口中的方法类似,他显式的说明了修饰的方法,在当前是没有实现体的,abstract的方法的实现体都由子类重写),只不过native方法调用的实现体,都是非java代码编写的(例如:调用的是在jvm中编写的C的接口),每一个native方法在jvm中都有一个同名的实现体,native方法在逻辑上的判断都是由实现体实现的,另外这种native修饰的方法对返回类型,异常控制等都没有约束。
由此可见,这里判断是否实现cloneable接口,是在调用jvm中的实现体时进行判断的。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)