什么是克隆

克隆就是依据已经有的数据,创造一份新的完全一样的数据拷贝。

浅克隆和深克隆区别

  • 浅克隆: 被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中的实现体时进行判断的。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐