引用与深浅克隆

本文详细探讨了Java中对象克隆的概念,包括引用与克隆的区别。通过实例解析了浅克隆和深克隆的实现方式及它们在处理复杂对象时的不同效果。浅克隆仅复制对象本身,而不复制其引用的对象,而深克隆则递归复制所有关联对象,确保独立性。文章强调了实现`Cloneable`接口的重要性,并提供了相关代码示例以加深理解。
摘要由CSDN通过智能技术生成

1. 克隆与引用

1.2 引用

在了解深克隆与浅克隆的区别之前,需先了解克隆与引用的区别。

我们通常通过"="对非八大数据和String类型的类进行赋值操作,这就是引用

如:

public class Student{
	private String name;
	private int age;
	
	public Student() {
		super();
	}

	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

再在测试类中进行测试,比较两个对象是否为同一个对象,也可以通过调试去查看地址是否相等

public class CloneTest {
	public static void main(String[] args) {
		Student s1 = new Student("Haku",16);
		Student s2 = s1;
		System.out.println(s1 == s2);
	}
}

结果很明显是true(调试可以明显看出两个对象的内存地址是一样的),并且修对象s2的属性值时,s1的相同属性值也会发生改变

	s2.setName("Sloth");
	System.out.println(s1.getName() == s2.getName());

结果同样也为true,明明没有修改s1的属性值,s1的属性值却被修改了,而且当我们销毁s2对象时,s1也会被同时销毁,也就是内存泄露。为了避免这种情况,通常会在创建类时实现Cloneable接口来实现克隆。

1.2 克隆

在所有java的主类Object中有一个方法Clone()克隆,我们通过在Student类中对Clone()方法的重写来实现克隆,重写方法具体如下:

public class Student implements Cloneable{
	@Override
	public Object clone(){
		
		Student student = null;
		try {
			student = (Student)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return student;
	}
}

修改下测试类

public class CloneTest {
	public static void main(String[] args) {
		Student s1 = new Student("Haku",16);
		Student s2 = (Student) s1.clone();
		System.out.println(s1 == s2);
	}
}

结果显而易见的为false,两者不为同一个对象

1.2.1 Cloneable接口有何用

空接口

当我们点开Cloneable查看其代码时,会发现其实它是一个空接口,当我们去掉implements Cloneable是再运行上述代码时,会发现报错java.lang.CloneNotSupportedException: myclone.Student
报错信息
我们再去jdk的api中查看Clone()方法发现
CloneNotSupportedException - 如果对象的类不支持Cloneable接口。 覆盖clone方法的子类也可以抛出此异常以指示实例无法克隆。
所以再进行克隆时一定要实现Cloneable接口,即便它是一个空接口
jdk_api

2 浅克隆与深克隆

2.1 浅克隆与深克隆的区别

  1. 浅克隆:对自定义类中没有有指向自定义类的克隆操作为浅克隆。对当前对象进行克隆,并克隆该对象所包含的8种基本数据类型和String数据类型;但如果被克隆对象中包括含除八种数据类型和String类型外的其它数据的属性,浅克隆不会进行赋值而是拷贝。
  2. 深克隆:自定义类中有指向自定义类的克隆操作为深克隆。深克隆是在浅克隆的基础上,递归地克隆除8种基本数据类型和String类型外的属性,为这些属性重写分配内存而非引用。

2.2 浅克隆

我们再创建一个类Teacher 其中属性有(String name,int age,Student student)并实现Cloneable接口重写Clone()方法:

public class Teacher implements Cloneable{
	private String name;
	private int age;
	private Student student;
	public Teacher() {
		super();
	}
	public Teacher(String name, int age, Student student) {
		super();
		this.name = name;
		this.age = age;
		this.student = student;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Student getStudent() {
		return student;
	}
	public void setStudent(Student student) {
		this.student = student;
	}
	@Override
	protected Object clone(){
		Teacher teacher = null;
		try {
			teacher = (Teacher)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return teacher;
	}
}

再调用测试类主函数

public static void main(String[] args) {
	Student s1 = new Student("Haku",16);
	Teacher t1 = new Teacher("Sloth",28,s1);
	Teacher t2 = (Teacher)t1.clone();
	
	System.out.println(t1 == t2);
	System.out.println(t1.getStudent() == t2.getStudent());
}

结果打印为:

false
true

Teacher的克隆成功了,但Teacher的属性student却没成功克隆,属于同一个对象,这就是浅克隆

那如何浅克隆修改为深克隆呢?

2.3 深克隆

我们修改一下Teacher的Clone()方法

@Override
protected Object clone(){
	Teacher teacher = null;
	try {
		teacher = (Teacher)super.clone();
		teacher.student = (Student)this.student.clone();
	} catch (CloneNotSupportedException e) {
		e.printStackTrace();
	}
	return teacher;
}

让student属性也被克隆

再调用测试类

结果为:

false
false

t1 和 t2 不是同一个对象,同时t1.student与t2.student也不是同一个对象这就是深克隆。

总结

  1. 引用:对象A在引用对象B时,当对象A的属性发生改变时对象B的属性也会同时发生改变,因为二者实际上为同一个对象。
  2. 浅克隆:对象A在克隆对象B时,当对象A的属性发生改变时对象B的属性不会同时发生改变;但若存在非八大类和Sting的数据类型的属性时,若在对象A中修改这些属性,则对象B也会发生改变。因为克隆的不完全,所以被称为浅克隆
  3. 深克隆:深克隆是在浅克隆的基础上进行了,改进,使得每个类型的属性都被完全克隆。

以上内容都是笔者对于深浅克隆与引用的一些拙见,如有不当,还请诸位斧正。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值