概念:就是对对象的拷贝
浅拷贝:数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型
深拷贝:引用类型包括类、接口、数组等复杂类型。
浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制
java自带一种克隆模式 不过那种克隆是属于浅拷贝(实现cloneable接口)
当使用java中覆盖object中的clone方法时,其中引用对象复制的是地址(也就是说地址值和复制之前的一样,然后指向同一个对象),而不是new一个新的地址。
深拷贝的话 复制的对象是新的 复制的引用对象也是新的。
**在Java语言中,如果需要实现深克隆,可以通过序列化(Serialization)等方式来实现。**序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。下面我们使用深克隆技术来实现工作周报和附件对象的复制,由于要将附件对象和工作周报对象都写入流中,因此两个类均需要实现Serializable接口
修改后的附件类Attachment代码如下:
import java.io.*;
//附件类
class Attachment implements Serializable
{
private String name; //附件名
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return this.name;
}
public void download()
{
System.out.println("下载附件,文件名为" + name);
}
}
工作周报类WeeklyLog不再使用Java自带的克隆机制,而是通过序列化来从头实现对象的深克隆,我们需要重新编写clone()方法,修改后的代码如下:
import java.io.*;
//工作周报类
class WeeklyLog implements Serializable
{
private Attachment attachment;
private String name;
private String date;
private String content;
public void setAttachment(Attachment attachment) {
this.attachment = attachment;
}
public void setName(String name) {
this.name = name;
}
public void setDate(String date) {
this.date = date;
}
public void setContent(String content) {
this.content = content;
}
public Attachment getAttachment(){
return (this.attachment);
}
public String getName() {
return (this.name);
}
public String getDate() {
return (this.date);
}
public String getContent() {
return (this.content);
}
//使用序列化技术实现深克隆
public WeeklyLog deepClone() throws IOException, ClassNotFoundException, OptionalDataException
{
//将对象写入流中
ByteArrayOutputStream bao=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bao);
oos.writeObject(this);
//将对象从流中取出
ByteArrayInputStream bis=new ByteArrayInputStream(bao.toByteArray());
ObjectInputStream ois=new ObjectInputStream(bis);
return (WeeklyLog)ois.readObject();
}
}
客户端代码如下所示:
class Client
{
public static void main(String args[])
{
WeeklyLog log_previous, log_new = null;
log_previous = new WeeklyLog(); //创建原型对象
Attachment attachment = new Attachment(); //创建附件对象
log_previous.setAttachment(attachment); //将附件添加到周报中
try
{
log_new = log_previous.deepClone(); //调用深克隆方法创建克隆对象
}
catch(Exception e)
{
System.err.println("克隆失败!");
}
//比较周报
System.out.println("周报是否相同? " + (log_previous == log_new));
//比较附件
System.out.println("附件是否相同? " + (log_previous.getAttachment() == log_new.getAttachment()));
}
}
编译并运行程序,输出结果如下:
周报是否相同? false
附件是否相同? false
从输出结果可以看出,由于使用了深克隆技术,附件对象也得以复制,因此用“==”比较原型对象的附件和克隆对象的附件时输出结果均为false。深克隆技术实现了原型对象和克隆对象的完全独立,对任意克隆对象的修改都不会给其他对象产生影响,是一种更为理想的克隆实现方式。
原型管理器
关键在于管理器中创建一个 hashmap来存储复制的对象 且改为单例模式
原型管理器(Prototype Manager)是将多个原型对象存储在一个集合中供客户端使用,它是一个专门负责克隆对象的工厂,其中定义了一个集合用于存储原型对象,如果需要某个原型对象的一个克隆,可以通过复制集合中对应的原型对象来获得。在原型管理器中针对抽象原型类进行编程,以便扩展。
import java.util.*;
//抽象公文接口,也可定义为抽象类,提供clone()方法的实现,将业务方法声明为抽象方法
interface OfficialDocument extends Cloneable
{
public OfficialDocument clone();
public void display();
}
//可行性分析报告(Feasibility Analysis Report)类
class FAR implements OfficialDocument
{
public OfficialDocument clone()
{
OfficialDocument far = null;
try
{
far = (OfficialDocument)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println("不支持复制!");
}
return far;
}
public void display()
{
System.out.println("《可行性分析报告》");
}
}
//软件需求规格说明书(Software Requirements Specification)类
class SRS implements OfficialDocument
{
public OfficialDocument clone()
{
OfficialDocument srs = null;
try
{
srs = (OfficialDocument)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println("不支持复制!");
}
return srs;
}
public void display()
{
System.out.println("《软件需求规格说明书》");
}
}
//原型管理器(使用饿汉式单例实现)
class PrototypeManager
{
//定义一个Hashtable,用于存储原型对象
private Hashtable ht=new Hashtable();
private static PrototypeManager pm = new PrototypeManager();
//为Hashtable增加公文对象
private PrototypeManager()
{
ht.put("far",new FAR());
ht.put("srs",new SRS());
}
//增加新的公文对象
public void addOfficialDocument(String key,OfficialDocument doc)
{
ht.put(key,doc);
}
//通过浅克隆获取新的公文对象
public OfficialDocument getOfficialDocument(String key)
{
return ((OfficialDocument)ht.get(key)).clone();
}
public static PrototypeManager getPrototypeManager()
{
return pm;
}
}
客户端代码如下所示:
class Client
{
public static void main(String args[])
{
//获取原型管理器对象
PrototypeManager pm = PrototypeManager.getPrototypeManager();
OfficialDocument doc1,doc2,doc3,doc4;
doc1 = pm.getOfficialDocument("far");
doc1.display();
doc2 = pm.getOfficialDocument("far");
doc2.display();
System.out.println(doc1 == doc2);
doc3 = pm.getOfficialDocument("srs");
doc3.display();
doc4 = pm.getOfficialDocument("srs");
doc4.display();
System.out.println(doc3 == doc4);
}
}
编译并运行程序,输出结果如下:
《可行性分析报告》
《可行性分析报告》
false
《软件需求规格说明书》
《软件需求规格说明书》
false