码迷,mamicode.com
首页 > 编程语言 > 详细

Java的深克隆与浅克隆

时间:2016-05-07 07:45:41      阅读:249      评论:0      收藏:0      [点我收藏+]

标签:

1.Java的基本数据类型和引用数据类型

基本数据类型包括byte、int、char、long、float、double、boolean和short八种基本数据类型 创建的对象在Java虚拟机栈中,

引用数据类型创建对象的时候会创建两个对象,一个在栈中,一般称作 ‘‘引用“,另一个存放在Java堆中。

2.浅克隆与深克隆

浅克隆的外在表现是:对象的基础类型对象相同,引用对象相同,包括存放在堆里的对象。也就是说所有的对其他对象的引用仍然指向原来的对象。

深克隆的外在表现是:复制前后的对象是相等的,也就是说引用的对象是相等的,而不是同一块Java堆中的内存。

对于对象来说相同和相等是充分不必要条件,相同一定相等,相等确往往可能不相同。

浅克隆是发生在栈中的拷贝,深克隆包括堆中对象的引用对象的拷贝。

3.Java对象的clone研究

<span style="font-family:Courier New;">package com.dusk.bean;

public class Student implements Cloneable{
	private String id;
	private Address address;
	public Student(){
	}
	public Student(String id){
		this.id=id;
	}
	public String getId() {
		return id;
	}
	
	public Address getAddress() {
		return address;
	}
	public void setAddress(Address address) {
		this.address = address;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + "]";
	}

	public void sayHello(){
		System.out.println("hello,everyone!");
	}
	@Override
	public Student clone() throws CloneNotSupportedException {
		return (Student) super.clone();
	}
	
}</span>
Address.java

<span style="font-family:Courier New;">package com.dusk.bean;

public class Address {
<span style="white-space:pre">	</span>private String address;
<span style="white-space:pre">	</span>public String getAddress() {
<span style="white-space:pre">		</span>return address;
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>public void setAddress(String address) {
<span style="white-space:pre">		</span>this.address = address;
<span style="white-space:pre">	</span>}</span>
}


Client.java

<span style="font-family:Courier New;">package com.dusk;

import org.junit.Test;

import com.dusk.bean.Student;

public class Client {
	@Test
	public void test() throws Exception {
		Student stu1=new Student("1");
		Student stu2=stu1.clone();
		System.out.println(stu1==stu2);
		System.out.println(stu1.getAddress()==stu2.getAddress());
	}
}</span>
运行结果:

<span style="font-family:Courier New;">false
true
</span>

结论: Object提供的clone方法默认是浅克隆操作,对Student对象中的address没有进行clone操作。

4.同理对System.arraycopy进行验证,上代码:

<span style="font-family:Courier New;">package com.dusk;

import org.junit.Test;

import com.dusk.bean.Student;

public class Test5 {
	@Test
	public void test() {
		Student[] arr1=new Student[]{new Student("1"),new Student("2"),new Student("3"),new Student("4")};
		Student[] arr2=new Student[4];
		System.arraycopy(arr1, 0, arr2, 0, 4);
		for(int i=0;i<arr2.length;i++){
			System.out.println(arr1[i]==arr2[i]);
		}
	}

}

</span>
运行结果:

<span style="font-family:Courier New;">true
true
true
true</span>

发现,System.arraycopy提供的也是浅克隆。

如果实现深克隆怎么办? 答案就是自己重写clone方法。

例如:

<span style="font-family:Courier New;"><span style="white-space:pre">	</span>@Override
	public Student clone() throws CloneNotSupportedException {
		Student stu=new Student();
		stu.setId(this.id);
		stu.setAddress(new Address());
		return stu;
	}</span>
结果肯定是:

<span style="font-family:Courier New;">false
false</span>
是不是到此为止了?怎么可能,

如果我们把Address也实现了Cloneable怎么样?

Address.java变身为

<span style="font-family:Courier New;">package com.dusk.bean;

public class Address implements Cloneable{

	@Override
	protected Object clone() throws CloneNotSupportedException {
		// TODO Auto-generated method stub
		return super.clone();
	}

}</span>
继续调用3中的场景, 结果是:

<span style="font-family:Courier New;">false
true
</span>
技术分享尽然不是我预想的递归调用,看来如果自己的对象引用比较深的情况下做深克隆,自能自己退下自己的苦果了。

只能这样了吗技术分享

看我必杀技,ObjectOutputStream和ObjectInputStream,祭法宝:


<span style="font-family:Courier New;">package com.dusk;

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

import org.junit.Test;

import com.dusk.bean.Address;
import com.dusk.bean.Student;

public class Client{
	@Test
	public void test() throws CloneNotSupportedException {
		Student stu1=new Student("1");
		Address add = new Address();
		stu1.setAddress(add);
		Student stu2=(Student) deepCopy(stu1);
		System.out.println(stu1==stu2);
		System.out.println(stu1.getAddress()==stu2.getAddress());
	}
	
	private Object deepCopy(Object obj){
		//将对象写到流里 
		try {
		 ByteArrayOutputStream bo=new ByteArrayOutputStream(); 
		 ObjectOutputStream oo;
			oo = new ObjectOutputStream(bo);
		 oo.writeObject(obj); 
		 //从流里读出来 
		 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
		 ObjectInputStream oi=new ObjectInputStream(bi); 
		 return(oi.readObject()); 
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return obj;
	}
}</span>

结果:

<span style="font-family:Courier New;">false
false</span>


完美的解决了对象多次套用的深克隆问题。


只要思想不滑坡,办法总比困难多!








Java的深克隆与浅克隆

标签:

原文地址:http://blog.csdn.net/jiaotuwoaini/article/details/51329680

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!