java深浅克隆

1.首先理解下浅克隆和深克隆的含义吧:

浅克隆:简单说就是对当前要克隆的对象的复制,但是不会复制当前对象对其他对象的引用,即引用还是指向之前被引用对象的地址。

深克隆:就是把要克隆对象以及他所有引用对象全部复制一份。

2.浅克隆的代码演示:通过这段代码你就会明白浅克隆到底是什么意思了。

class Teacher{
	public String name;
	public int age;
	public Teacher(String name,int age){
		this.name = name;
		this.age = age;
	}
}
class Student implements Cloneable{
	public String name;
	public int age;
	public Teacher teacher;
	public Student(String name,int age,Teacher t){
		this.name = name;
		this.age = age;
		this.teacher = t;
	}
	
	@Override
	public Student clone() throws CloneNotSupportedException {
		Student s= (Student)super.clone();
		return s;
	}
}
public class TestClone {
	public static void main(String[] args) throws Exception {
		Teacher teacher = new Teacher("Job",50);
		Student stu1 = new Student("Kobe",24,teacher);
		Student stu2 =  stu1.clone();
		System.out.println("stu1 == stu2?-->" + (stu1 == stu2));
		System.out.println("stu1[name = "+ stu1.name + ",age = " + stu1.age 
				+ "],stu2[name = " + stu2.name + ",age = " + stu2.age + "]");
		System.out.println("stu1.teacher == stu2.teacher?-->" 
				+ (stu1.teacher == stu2.teacher));
		/**
		 * 此处改变stu2引用对象的值,会改变stu1引用对象的值
		 * 
		 */
		stu2.teacher.name = "Mike";
		stu2.teacher.age = 60;
		System.out.println("stu1[name = " + stu1.teacher.name 
				+ ",age = " + stu1.teacher.age + "]");
	}
}

java深浅克隆_第1张图片

 

由上段代码的结果可以看出:stu1和stu2的内存地址不同,只是形成了值得拷贝,Student对象中的Teacher对象的引用没有改变。一旦改变stu2引用Teacher的值,stu1所引用的Teacher的值也会改变,其实他俩指向的是同一内存地址,这就是所谓的浅克隆。

顺便说一下Object基类中clone()方法的含义:Object中的clone()方法可以识别出我们要复制的是哪一个对象,然后会为此对象分配内存空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。

 引用下官网API的一段话:

The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.

 

3.深克隆代码的演示:

先来一段代码:

 

class Teacher implements Cloneable{
	public String name;
	public int age;
	public Teacher(String name,int age){
		this.name = name;
		this.age = age;
	}
	@Override
	public Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
class Student implements Cloneable{
	public String name;
	public int age;
	public Teacher teacher;
	public Student(String name,int age,Teacher t){
		this.name = name;
		this.age = age;
		this.teacher = t;
	}
	
	@Override
	public Student clone() throws CloneNotSupportedException {
		Student s= (Student)super.clone();
		s.teacher = (Teacher)teacher.clone();
		return s;
	}
}
public class TestClone {
	public static void main(String[] args) throws Exception {
		Teacher teacher = new Teacher("Job",50);
		Student stu1 = new Student("Kobe",24,teacher);
		Student stu2 =  stu1.clone();
		System.out.println("stu1 == stu2?-->" + (stu1 == stu2));
		System.out.println("stu1[name = "+ stu1.name + ",age = " + stu1.age 
				+ "],stu2[name = " + stu2.name + ",age = " + stu2.age + "]");
		System.out.println("stu1.teacher == stu2.teacher?-->" 
				+ (stu1.teacher == stu2.teacher));
		/**
		 * 此处改变stu2引用对象的值,不会改变stu1引用对象的值,因为在Student的clone()方法中已经对引用Teacher进行了复制。
		 * 
		 */
		stu2.teacher.name = "Mike";
		stu2.teacher.age = 60;
		System.out.println("stu1[name = " + stu1.teacher.name 
				+ ",age = " + stu1.teacher.age + "]");
	}
}

java深浅克隆_第2张图片
 

从结果可以看出改变stu2引用对象属性的值,stu1中的引用对象属性值并没有改变,这在要拷贝对象中引用对象内部没有其他引用的时候是成立的,如果Teacher中有其他对象的引用,则这样又会产生浅克隆的现象,这样并不能叫做深克隆,除非一层层的拷贝下去,所以网上很多举例解释是错误的。

 

还有一种是通过串行化来进行深拷贝,也就是流的过程。把对象写入流--->串行化,从流中读出对象--->并行化,对象本身还是存在于JVM中,流也是对对象的一种拷贝。代码如下:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class Teacher implements Serializable{
	private static final long serialVersionUID = 1L;
	public String name;
	public int age;
	public Teacher(String name,int age){
		this.name = name;
		this.age = age;
	}
}
class Student implements Serializable{
	private static final long serialVersionUID = 1L;
	public String name;
	public int age;
	public Teacher teacher;
	public Student(String name,int age,Teacher t){
		this.name = name;
		this.age = age;
		this.teacher = t;
	}
	public Object deepClone()throws Exception{
		ByteArrayOutputStream bos=new ByteArrayOutputStream();
		ObjectOutputStream oos=new ObjectOutputStream(bos);
		oos.writeObject(this);//从流里读出来
		ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois=new ObjectInputStream(bis);
		return(ois.readObject());
	}
}
public class TestClone {
	public static void main(String[] args) throws Exception {
		Teacher teacher = new Teacher("Job",50);
		Student stu1 = new Student("Kobe",24,teacher);
		Student stu2 =  (Student)stu1.deepClone();
		System.out.println("stu1 == stu2?-->" + (stu1 == stu2));
		System.out.println("stu1[name = "+ stu1.name + ",age = " + stu1.age 
				+ "],stu2[name = " + stu2.name + ",age = " + stu2.age + "]");
		System.out.println("stu1.teacher == stu2.teacher?-->" 
				+ (stu1.teacher == stu2.teacher));
		/**
		 * 此处改变stu2引用对象的值,不会改变stu1引用对象的值
		 * 
		 */
		stu2.teacher.name = "Mike";
		stu2.teacher.age = 60;
		System.out.println("stu1[name = " + stu1.teacher.name 
				+ ",age = " + stu1.teacher.age + "]");
	}
}

 
java深浅克隆_第3张图片
从结果可以看出改变stu2引用对象属性的值,stu1中的引用对象属性值并没有改变,这种方法也可以实现深拷贝(前提是所有引用对象都必须可序列化,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外)

 

ok,深浅克隆到此结束,可以下班回家了,吼吼

 

 

你可能感兴趣的:(java基础,java)