java 克隆

如果希望一个类能够克隆,那么:
(1) 实现Cloneable 接口
(2) 覆盖clone()    需要申明为public;只覆盖方法而不实现接口,则会抛出异常CloneNotSupportedException
(3) 在自己的clone()中调用super.clone()
(4) 在自己的clone()中捕获违例
这一系列步骤能达到最理想的效果。

 

java浅复制:

package com.soft.clone;

public class CloneTest implements Cloneable 
{
	private Entity entity;
	private int tmp;
	
	public CloneTest(Entity entity,int tmp) 
	{
		this.entity = entity;
		this.tmp = tmp;
	}
	
	public Object clone()
	{
		Object o = null;
		try 
		{
			o = super.clone();
		} catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		return o;
	}
	
	public void increment()
	{
		tmp++;
	}
	
	public int getTmp() {
		return tmp;
	}

	public Entity getEntity() {
		return entity;
	}
	
	public static void main(String[] args) 
	{
		Entity entity = new Entity(6);
		CloneTest test1 = new CloneTest(entity, 1);
		CloneTest test2 = (CloneTest)test1.clone();
		test2.increment();
		test2.getEntity().increment();
		System.out.println("test1.tmp = " + test1.getTmp());
		System.out.println("test1.Entity.i = " + test1.getEntity().getI());
		System.out.println("test2.tmp = " + test2.getTmp());
		System.out.println("test2.Entity.i = " + test2.getEntity().getI());
		
	}
	
}

class Entity
{
	private int i;
	
	public Entity(int i) 
	{
		this.i = i;
	}
	
	public void increment()
	{
		i++;
	}

	public int getI() {
		return i;
	}
	
}


输出结果:

test1.tmp = 1
test1.Entity.i = 7
test2.tmp = 2
test2.Entity.i = 7

 

浅复制只会复制对象的基本类型成员。若对象中包含其他对象作为成员变量(上例中的entity),则只复制entity的引用,实际指向的是同一个实例。

 

thinking in java 4th 12章

       最初,Java 只是作为一种用于控制硬件的语言而设计,与因特网并没有丝毫联系。象这样一类面向大众的语言一样,其意义在于程序员可以对任意一个对象进行克隆。这样一来,clone()就放置在根类Object 里面,但因为它是一种公用方式,因而我们通常能够对任意一个对象进行克隆。看来这是最灵活的方式了,毕竟它不会带来任何害处。
       正当Java 看起来象一种终级因特网程序设计语言的时候,情况却发生了变化。突然地,人们提出了安全问题,而且理所当然,这些问题与使用对象有关,我们不愿望任何人克隆自己的保密对象。所以我们最后看到的是为原来那个简单、直观的方案添加的大量补丁:clone()在Object 里被设置成“protected”。必须将其覆盖,并使用“implement Cloneable”,同时解决违例的问题。只有在准备调用Object 的clone()方法时,才没有必要使用Cloneable 接口,因为那个方法会在运行期间得到检查,以确保我们的类实现了Cloneable。但为了保持连贯性(而且由于Cloneable 无论如何都是空的),最好还是由自己实现Cloneable。

 

java深层复制:

试图深层复制合成对象时会遇到一个问题。必须假定成员对象中的clone()方法也能依次对自己的句柄进行深层复制,以此类推。

为了能正常实现深层复制,必须对所有类中的代码进行控制,或者至少全面掌握深层复制中需要涉及的类,确保它们自己的深层复制能正确进行。

 

java深层复制方法有两种:

1、使用序列化深复制

2、克隆合成对象时候,将合成对象对象所拥有的句柄也进行深层复制

import java.io.Serializable;
//方式一:序列化
public class Thing2 implements Serializable
{
	Thing1 o1 = new Thing1();
}


class Thing1 implements Serializable
{
}


 

public class Thing4 implements Cloneable
{
	Thing3 o3 = new Thing3();
	
	//方式二:clone方法中对成员变量(成员对象是一个句柄)也进行克隆	
	public Object clone()
	{
		Thing4 o = null;
		try 
		{
			//此处明确克隆后的对象为Thing4,为了能够访问成员变量,对成员变量也进行复制
			o = (Thing4)super.clone();
		} catch (Exception e) 
		{
			e.printStackTrace();
		}
		o.o3 = (Thing3)o3.clone();
		return o;
	}
	
}

class Thing3 implements Cloneable
{
	public Object clone()
	{
		Object o = null;
		try 
		{
			o = super.clone();
		} catch (Exception e) 
		{
			e.printStackTrace();
		}
		
		return o;
	}
}



 

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

public class Compete
{
	static final int SIZE = 5000;
	public static void main(String[] args) 
	{
		
		Thing2[] a = new Thing2[SIZE];
		for (int i = 0; i < a.length; i++) 
		{
			a[i] = new Thing2();
		}
		
		Thing4[] b = new Thing4[SIZE];
		for (int i = 0; i < b.length; i++) 
		{
			b[i] = new Thing4();
		}
		
		try 
		{
			long t1 = System.currentTimeMillis();
			ByteArrayOutputStream buf = new ByteArrayOutputStream();
			ObjectOutputStream o = new ObjectOutputStream(buf);
			for (int i = 0; i < a.length; i++) 
			{
				o.writeObject(a[i]);
			}
			
			//now get copies
			ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()));
			Thing2[] c = new Thing2[SIZE];
			for (int i = 0; i < c.length; i++) 
			{
				c[i] = (Thing2)in.readObject();
			}
			
			long t2 = System.currentTimeMillis();
			System.out.println("Duplication via serialization:" 
					+ (t2 - t1) + " Milliseconds");
			
			
			//clone
			t1 = System.currentTimeMillis();
			Thing4[] d = new Thing4[SIZE];
			for (int i = 0; i < d.length; i++) 
			{
				d[i] = (Thing4)b[i].clone();
			}
			t2 = System.currentTimeMillis();
			System.out.println("Duplication via cloning:" 
					+ (t2 - t1) + " Milliseconds");
		} catch (Exception e) 
		{
		}
	}
}


输出结果:

运行第一次结果:

Duplication via serialization:81 Milliseconds
Duplication via cloning:3 Milliseconds

运行第二次结果:

Duplication via serialization:76 Milliseconds
Duplication via cloning:3 Milliseconds

 

Serializable 类很容易设置,但在复制它们时却要做多得多的工作。克隆涉及到大量的类设置工作,但实际的对象复制是相当简单的。


除了序列化和克隆之间巨大的时间差异以外,我们也注意到序列化技术的运行结果并不稳定,而克隆每一次花费的时间都是相同的。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值