深浅拷贝

转载:详解Java中的clone方法

 虽然是转载,这里大概说一下自己的理解:

  无论是深拷贝还是浅拷贝,只要是想让对象具有拷贝的功能,当前类必须实现Cloneable接口(说明该类具有clone的性质,如果不实现会抛出CloneNotSupportedException异常),并在类中覆写Object类的clone()方法(并且设置访问限定符为public),该方法是需要在别的类中被调用的
  对于基本数据类型来说,无论哪种拷贝,都是将值进行传递,肯定会新开一块内存空间存储该值,并将该值赋给新的引用变量。而对于引用类型来讲,若只是简单的将引用赋值给新的变量(实际上拷贝前后对象的属性引用指向同一块内存空间),这样就是浅拷贝;而若新创建一个属性与原对象完全相同的对象(拷贝前后对象的属性引用指向不同的内存空间),这样就是深拷贝。
  Object类中默认的clone()方法采用的是浅拷贝,若需要实现深拷贝需要在覆写的clone()方法中添加属性是引用数据类型的克隆,如果属性是引用数据类型,则要要实现深拷贝就需要实现一条"引用链"。

 这里做一点补充:

  深拷贝除了可以采用文中对所有"引用链"中的每一级对象都要进行显示的拷贝外,还可以采用序列化与反序列化的方式进行对象的深拷贝
  要使用序列化的方式实现深拷贝,必须保证该类(Student)及其引用属性类(Teacher)都必须实现Serializable接口(也就是整个引用链的所有类),否则会报NotSerializableException异常。通过将当前对象序列化为字节数组存放在内存中,再将内存中的字节数组反序列化为对象(借助内存流),从而实现深拷贝。


 实例:

  浅拷贝:

package com.xiaoaxiao.test.clone_test;

/**
 * Created by xiaoaxiao on 2019/12/17
 * Description: 浅拷贝
 *          直接调用当前对象的clone(),当前对象会是直接被拷贝,
 *          但当前对象内部属性是引用数据类型的对象并不会被拷贝(只是引用传递)
 */

	class Person implements Cloneable{
	
	    private Face face;
	    private int age;
	
	
	    public Person(Face face, int age) {
	        this.face = face;
	        this.age = age;
	    }
	
	    public Face getFace() {
	        return face;
	    }
	
	    @Override
	    protected Object clone() throws CloneNotSupportedException {
	        return super.clone();
	    }
	}
	
	class Face{
	
	}
	
	public class ShallowClone {
	    public static void main(String[] args) throws CloneNotSupportedException {
	        Person person1 = new Person(new Face(),30);
	
	        Person person2 = (Person)person1.clone();
	
	        System.out.println(person1==person2);
	        System.out.println(person1.getFace()==person2.getFace());
	    }
	}

	// 输出
		false
		true(对象的属性只是引用的变化,实际上指向的是同一个地址)

  深拷贝:

	package com.xiaoaxiao.test.clone_test;
	
	/**
	 * Created by xiaoaxiao on 2019/12/17
	 * Description: 深拷贝
	 *          要想实现深拷贝,就得在当前对象的clone()方法中将其属性对象也完全拷贝一份,
	 *          这就要求其属性对象必须覆写clone()
	 */
	
	class Animal implements Cloneable{
	    private Body body;
	
	    public Animal(Body body) {
	        this.body = body;
	    }
	
	    public Body getBody() {
	        return body;
	    }
	
	    public void setBody(Body body) {
	        this.body = body;
	    }
	
	    @Override
	    protected Object clone() throws CloneNotSupportedException {
	        Animal newAnimal = (Animal)super.clone();
	        // 引用数据类型的属性进行拷贝
	        Body newBody = (Body)body.clone();
	        newAnimal.setBody(newBody);
	        return newAnimal;
	    }
	}
	
	class Body implements Cloneable{
	
	    @Override
	    protected Object clone() throws CloneNotSupportedException {
	        return super.clone();
	    }
	}
	
	public class DeepClone {
	    public static void main(String[] args) throws CloneNotSupportedException {
	        Animal animal1 = new Animal(new Body());
	        Animal animal2 = (Animal)animal1.clone();
	
	        System.out.println(animal1==animal2);
	        System.out.println(animal1.getBody()==animal2.getBody());
	    }
	}
	
	// 输出
		false
		false

  序列化与反序列化实现深拷贝:

	class Student implements Serializable{
	    private Teacher teacher;
	
	    public Student(Teacher teacher) {
	        this.teacher = teacher;
	    }
	
	    public Teacher getTeacher() {
	        return teacher;
	    }
	
	    /**
	     * 为了体现封装性,将这些序列化与反序列化的操作放在该类中,该类向外提供一个方法以供深拷贝即可。
	     */
	    public Student cloneObject() throws IOException, ClassNotFoundException {
		        // 通过内存流进行序列化,将对象序列化为字节数组存放在内存中
		        ByteOutputStream baos = new ByteOutputStream();
		        ObjectOutputStream oos = new ObjectOutputStream(baos);
		        oos.writeObject(this);
		
		        // 通过内存流进行反序列化,将内存中的字节数组反序列化为对象
		        ByteArrayInputStream bais = new ByteArrayInputStream(baos.getBytes());
		        ObjectInputStream ois = new ObjectInputStream(bais);
		        Student newStu = (Student)ois.readObject();
		        return newStu;
	    }
	}

	class Teacher implements Serializable{
	
	}
	
	public class DeepCloneBySerializable  {
	    public static void main(String[] args) throws IOException, ClassNotFoundException {
	        Student student = new Student(new Teacher());
	
	        Student newStu = student.cloneObject();
	
	        System.out.println(student==newStu);
	        System.out.println(student.getTeacher()==newStu.getTeacher());
	    }
	}

		
	// 输出
		false
		false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值