深拷贝和浅拷贝的一点总结

浅拷贝

Java在复制一个对象的时候,对于其基本数据类型,复制了他的值;对于其引用数据类型,复制了他的引用,并没有重新new一个对象

如何实现浅拷贝

clone()方法

在 Java 中,所有的 Class 都继承自 Object ,而在 Object 上,存在一个 clone() 方法,它被声明为了native protected ,所以我们可以在其子类中,使用它,并且不用关心内部实现。
因为native关键字:用来修饰方法,被修饰后的方法,看不见方法体。底层调用了C/C++代码。
所有需要调用clone()的类都必须实现Cloneable,该接口没有抽象方法,理解成一个标记来表示允许被拷贝。

import java.io.Serializable;

public class Person implements Cloneable {
	public int age;
	public String name;
	public Student stu;
	public Person(int age, String name, Student stu) {
		super();
		this.age = age;
		this.name = name;
		this.stu = stu;
	}
	public Person() {
		super();
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
}

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

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IOException {
		Student s=new Student(19,"学生");
		Person p=new Person(20,"人",s);
		try {
			Person c = (Person)p.clone();
			System.out.println("拷贝前:");
			System.out.println("Person的年龄:"+p.age);
			System.out.println("Person的姓名:"+p.name);
			System.out.println("Student的年龄:"+p.stu.age);
			System.out.println("Student的姓名:"+p.stu.name);
		
			System.out.println("-----------------------------------");
			System.out.println("拷贝后:");
			System.out.println("Person的年龄:"+c.age);
			System.out.println("Person的姓名:"+c.name);
			System.out.println("Student的年龄:"+c.stu.age);
			System.out.println("Student的姓名:"+c.stu.name);
			System.out.println("age是否是相同:"+(c.age==p.age));
			System.out.println("name是否是为一个引用:"+(c.name==p.name));
			System.out.println("Student是否是一个引用:"+(c.stu==p.stu));
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}

运行结果:
可以看到Student、String这两个引用数据类型在拷贝后仍是一个引用,即没有new出新对象,基本数据类型是拷贝了一个值。
在这里插入图片描述

深拷贝

Java在复制一个对象的时候,对于其基本数据类型,复制了他的值;对于其引用数据类型,重新new一个对象,并复制了该引用类型的成员变量。

如何实现深拷贝

  • 序列化
    序列化这个对象再反序列化回来,就会得到一个新对象。

什么是序列化和反序列化?
序列化:把对象转为字节序列,对象的输出过程称为序列化。
反序列化:把字节序列转为对象,对象的读取过程称为反序列化。

import java.io.Serializable;

public class Person implements Serializable {
	public int age;
	public String name;
	public Student stu;
	public Person(int age, String name, Student stu) {
		super();
		this.age = age;
		this.name = name;
		this.stu = stu;
	}
	public Person() {
		super();
	}
	
}

//在序列化某个对象的过程中,属性是引用数据类型,引用数据类型也要实现Serializable
public class Student  implements Serializable{
	public int age;
	public String name;
	public Student(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}
	public Student() {
		super();
	}
	
}

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IOException {
		Student s=new Student(25,"学生");
		Person p=new Person(19,"人",s);
		System.out.println("序列化前:");
		System.out.println("Person的年龄:"+p.age);
		System.out.println("Person的姓名:"+p.name);
		System.out.println("Student的年龄:"+p.stu.age);
		System.out.println("Student的姓名:"+p.stu.name);
		FileOutputStream os=new FileOutputStream("Test.txt");
		ObjectOutputStream oos=new ObjectOutputStream(os);
		oos.writeObject(p);
		
		FileInputStream fis=new FileInputStream("Test.txt");
		ObjectInputStream ois=new ObjectInputStream(fis);
		Person readObject = (Person)ois.readObject();
		oos.close();
		os.close();
		ois.close();
		fis.close();
		
		System.out.println("-----------------------------------");
		System.out.println("序列化后:");
		System.out.println("Person的年龄:"+readObject.age);
		System.out.println("Person的姓名:"+readObject.name);
		System.out.println("Student的年龄:"+readObject.stu.age);
		System.out.println("Student的姓名:"+readObject.stu.name);
		System.out.println("age是否是相同:"+(readObject.age==p.age));
		System.out.println("name是否是为一个引用:"+(readObject.name==p.name));
		System.out.println("Student是否是一个引用:"+(readObject.stu==p.stu));
	}
}

运行结果:
从运行结果看出,这个Student类型成员变量和Sting类型成员变量均new了一个新的对象,而基本数据类型仅仅是复制了值给这个Person拷贝的新对象
在这里插入图片描述

  • clone()
public class Person implements Cloneable {
	public int age;
	public String name;
	public Student stu;
	public Person(int age, String name, Student stu) {
		super();
		this.age = age;
		this.name = name;
		this.stu = stu;
	}
	public Person() {
		super();
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Person pClone=(Person)super.clone();
		pClone.stu=(Student)pClone.stu.clone();//pClone的stu指向了stu的拷贝
		pClone.name=new String(pClone.name);//这里是为了让String这个引用数据类型也实现深拷贝
		return pClone;
	}
}

//Student实现Cloneable是为了在Person的clone()中可以拷贝一个新的Student,让Person的stu指向这个新的,来达到深拷贝的目的。即在深拷贝使用clone()时,该类中的成员变量是引用数据类型,该引用数据类型也要实现Cloneable
public class Student  implements Cloneable{
	public int age;
	public String name;
	public Student(int age, String name) {
		super();
		this.age = age;
		this.name = name;
	}
	public Student() {
		super();
	}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}
}

public class Test {
	public static void main(String[] args) throws ClassNotFoundException, IOException {
		Student s=new Student(19,"学生");
		Person p=new Person(20,"人",s);
		try {
			Person c = (Person)p.clone();
			System.out.println("拷贝前:");
			System.out.println("Person的年龄:"+p.age);
			System.out.println("Person的姓名:"+p.name);
			System.out.println("Student的年龄:"+p.stu.age);
			System.out.println("Student的姓名:"+p.stu.name);
		
			System.out.println("-----------------------------------");
			System.out.println("拷贝后:");
			System.out.println("Person的年龄:"+c.age);
			System.out.println("Person的姓名:"+c.name);
			System.out.println("Student的年龄:"+c.stu.age);
			System.out.println("Student的姓名:"+c.stu.name);
			System.out.println("age是否是相同:"+(c.age==p.age));
			System.out.println("name是否是为一个引用:"+(c.name==p.name));
			System.out.println("Student是否是一个引用:"+(c.stu==p.stu));
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

运行结果:
从这个结果可以看出,对于Student引用数据类型,使用clone()也可以进行深拷贝
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值