2011-04-16 10:58:00 xbl1986 阅读数 2183

linux下的select,注意咯,不是pselect。

select()函数的最后一个参数是timeout,用来设置超时用的。

用的是一个struct timeval结构,需要用到sys/time.h文件。

struct timeval {

long tv_sec; 秒

long tv_usec; 毫毛

}

 

设置了timeout的值之后呢,select在没有文件描述符监视可用的情况下,会等待这个timeout的时间,时间到了select返回0

如果timeout超时之前有文件描述符可用,则返回可用的数量,这时候的timeout则会依然计数,因此如果想要每次都超时一定的时间那么在slelect返回>0的值之后要重新装填timeout的值一次。以保证超时时间没有变化。

如果tv_sec和tv_usec都是0,那么就是超时时间为0,那么select就会立刻返回了。

如果timeout这里是个NULL,那么超时就未被启用,会一直阻塞在监视文件描述符的地方。

 

在pselect中的timeout更牛X

用到了struct timespec {

long tv_sec; 秒

long tv_nsec; 纳秒

}

时间更精确。

 

当然了系统做不了这么精确的事情,一般linux的系统精度也就是10ms左右了。

 

这里说的重点在于timeout的值的选择和处理上。

 

另外遇到的一个问题是信号SIGALRM会使得select返回-1并置errno为EINTR。但这个信号已经被我的sigaction干掉了函数处理了,这个问题还需要研究一下。

2020-04-06 14:22:35 JinYinSiShe 阅读数 14

clone和new

拿孙悟空来举例
clone只需要吹个毫毛就可以生成多个
new还需要多个石头才孕育出多个猴子 :)

clone在内存中复制已有对象的内存,不会经过构造函数
new则是通过开辟内存新建一个对象

那么谁的效率高呢,从文字来看应该是clone,实时是否如此呢,我们往下看

clone

public class ProtoType implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Test
    public void testClone() throws CloneNotSupportedException {
        ProtoType p = new ProtoType();
        ProtoType copy = (ProtoType) p.clone();
        log.info("p == copy: {}", p == copy);
    }
12:51:16.305 [main] INFO prototype.Run - p == copy: **false**

这里看到内存地址的确不同,为什么不用hashcode来代替验证可以参考这篇文章Java的Object.hashCode()的返回值到底是不是对象内存地址?

浅拷贝

实现Cloneable接口,空接口起标志作用
我们对象中加个引用类型字段

public class ProtoType implements Cloneable{

    List<Integer> list;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
	}
}

再看看字段的内存地址比较

@Test
    public void testShallowCopy() throws CloneNotSupportedException {
        ProtoType p = new ProtoType();
        p.list = new ArrayList<>();
        ProtoType copy = (ProtoType) p.clone();
        log.info("p.list == copy.list:{}", p.list == copy.list);
    }
11:04:49.045 [main] INFO prototype.Run - p.list == copy.list:  **false**

看到字段内存地址相同

这就是浅拷贝,对象中的引用类型字段clone时只是把引用对象的内存地址指向clone对象的字段,类似如下简易图

对象p 内存 对象copy
p 0001
p.list 0002 copy.list
0003 copy

深拷贝

有时我们希望clone出来的对象彼此独立,这时需要深拷贝
这里用到序列化,所以需要Serializable 接口

public class ProtoType implements Cloneable, Serializable {

    List<Integer> list;

    @Override
    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
        try {
            return deepCopy(); // 这里使用深拷贝方法
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return new Object();
    }
    // 关键方法
    private Object deepCopy() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(this); // 序列化当前对象

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        return ois.readObject(); // 反序列化
    }
}
14:06:41.844 [main] INFO prototype.Run - p.list == copy.list: false

浅拷贝效率

// 执行类
@Test
    public void testEffect() throws CloneNotSupportedException {
    // 100W次new和clone
        final int count = 1000000;

        long begin = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            new ProtoType();
        }
        log.info("new cost:{}", System.currentTimeMillis() - begin);

        ProtoType p = new ProtoType();
        begin = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
            p.clone();
        }
        log.info("clone cost:{}", System.currentTimeMillis() - begin);
    }
// ProtoType.java 
 @Override
 protected Object clone() throws CloneNotSupportedException {
     return super.clone();
 }
14:09:32.577 [main] INFO prototype.Run - new cost:110
14:09:32.606 [main] INFO prototype.Run - clone cost:22

深拷贝效率

执行类不变,clone变深拷贝

// ProtoType.java
@Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            return deepCopy();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return new Object();
    }
14:13:43.107 [main] INFO prototype.Run - new cost:23
14:13:53.613 [main] INFO prototype.Run - clone cost:10500

总结

因为这里深拷贝有IO的运算,所以耗时很长
其实效率来说并不是绝对的,还是取决于深拷贝和浅拷贝的需求,以及clone方法和构造方法的耗时情况

2019-10-19 22:32:00 sinat_21107433 阅读数 524

孙悟空拔一根毫毛就可以变出好多一模一样的孙悟空!!!中国的克隆技术其实是世界领先的!

即便Jungle读书少,Jungle也清晰地记得中学生物课本上提到过的克隆羊“多利”。虽然多利寿命不长,但它的出现对“克隆(Clone)”技术意义重大。克隆,直观说就是从原有生物体上取体细胞,然后无性繁殖出有完全相同基因的个体或种群。这么说来中国的克隆技术其实是世界领先的,因为孙悟空拔一根毫毛变出许多一模一样的孙悟空的传说本质上就是克隆!而本文将要介绍的原型模式,将克隆技术应用到了软件设计层面。

1.原型模式简介

原型模式通过复制一个已有对象来获取更多相同或者相似的对象。原型模式定义如下:

原型模式:

使用原型实例指定待创建对象的类型,并且通过复制这个原型阿里创建型的对象。

原型模式的工作原理是将一个原型对象传给要发动穿件的对象(即客户端对象),这个要发动创建的对象通过请求原型对象复制自己来实现创建过程。从工厂方法角度而言,创建新对象的工厂就是原型类自己。软件系统中有些对象的创建过程比较复杂,且有时需要频繁创建,原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象,这就是原型模式的意图所在。

2.原型模式结构

原型式的结构包含以下几个角色:

  • 抽象原型类(AbstractPrototype):声明克隆clone自身的接口
  • 具体原型类(ConcretePrototype):实现clone接口
  • 客户端(Client):客户端中声明一个抽象原型类,根据客户需求clone具体原型类对象实例

原型模式的UML图如下:

3.关于克隆方法:浅拷贝/深拷贝

原型模式可以说是“复制”,即克隆,但这个复制不是代码的复制,而是将对象包含的所有属性都创建一份拷贝。但不同的复制操作,可能会产生两种不同的拷贝,即浅拷贝和深拷贝。

3.1.浅拷贝

在浅拷贝中,如果原型对象的成员变量是值类型(如int、double、char等基本数据类型),将复制一份给拷贝对象;如果原型对象的成员变量是引用/指针,则将引用/指针指向的地址拷贝一份给拷贝对象,即原型对象和拷贝对象中的成员变量指向同一个地址

3.2.深拷贝

在深拷贝中,无论原型对象中的成员变量是值类型还是指针/引用类型,都将复制一份给拷贝对象。注意,深拷贝中,指针/引用对象也会被拷贝一份给拷贝对象

下图举例说明了浅拷贝与深拷贝的区别:

4.原型模式代码实例

明天就是周一了,Jungle又陷入了苦恼中,因为作业还没完成。于是Jungle想拿着哥哥Single的作业来抄一份。虽然抄袭作业并不好,但是边抄边学借鉴一下也是可以的。于是乎,Jungle开始动起手来……

 作业包含几个部分:姓名(name)、学号(idNum)、模型(workModel)。首先定义一个workModel类:

//work model类
class WorkModel
{
public:
	char *modelName;
	void setWorkModelName(char *iName){
		this->modelName = iName;
	}
};

该实例UML图如下:

 

4.1.定义原型类和克隆方法

//抽象原型类PrototypeWork
class PrototypeWork
{
public:
	PrototypeWork(){}
	virtual PrototypeWork *clone() = 0;

private:
	
};

//具体原型类ConcreteWork
class ConcreteWork :public PrototypeWork
{
public:
	ConcreteWork(){}
	ConcreteWork(char* iName, int iIdNum, char* modelName){
		this->name = iName;
		this->idNum = iIdNum;
		this->workModel = new WorkModel();
		this->workModel->setWorkModelName(modelName);
	}
	
	ConcreteWork *clone(){
		ConcreteWork *work = new ConcreteWork();
		work->setName(this->name);
		work->setIdNum(this->idNum);
		work->workModel = this->workModel;
		return work;
	}

	void setName(char* iName){
		this->name = iName;
	}
	void setIdNum(int iIdNum){
		this->idNum = iIdNum;
	}
	void setModel(WorkModel *iWorkModel){
		this->workModel = iWorkModel;
	}
	//打印work信息
	void printWorkInfo(){
		printf("name:%s\t\n", this->name);
		printf("idNum:%d\t\n", this->idNum);
		printf("modelName:%s\t\n", this->workModel->modelName);
	}
private:
	char* name;
	int idNum;
	WorkModel *workModel;
};

 4.2.客户端使用代码示例

4.2.1.示例一:浅拷贝

#include "PrototypePattern.h"

int main()
{
	ConcreteWork *singleWork = new ConcreteWork("Single",1001,"Single_Model");
	printf("\nSingle的作业:\n");
	singleWork->printWorkInfo();
	
	printf("\njungle直接抄作业……\n");
	ConcreteWork *jungleWork = singleWork;
	printf("\nJungle的作业:\n");
	jungleWork->printWorkInfo();

	//抄完改名字和学号,否则会被老师查出来
	printf("\njungle抄完改名字和学号,否则会被老师查出来……\n");
	jungleWork->setName("jungle");
	jungleWork->setIdNum(1002);
	WorkModel *jungleModel = new WorkModel();
	jungleModel->setWorkModelName("Jungle_Model");
	jungleWork->setModel(jungleModel);
	
	//检查下是否改对了
	printf("\nSingle的作业:\n");
	singleWork->printWorkInfo();
	printf("\nJungle的作业:\n");
	jungleWork->printWorkInfo();

	system("pause");
	return 0;
}

效果如下图:

显然,这不是我们想要的结果。接下来我们使用clone方法。 

4.2.2.示例二:深拷贝

#include "PrototypePattern.h"

int main()
{
	ConcreteWork *singleWork = new ConcreteWork("Single", 1001, "Single_Model");
	printf("\nSingle的作业:\n");

	ConcreteWork *jungleWork = singleWork->clone();
	printf("\nJungle的作业:\n");

	//抄完改名字和学号,否则会被老师查出来
	printf("\njungle抄完改名字和学号,否则会被老师查出来……\n");
	jungleWork->setName("jungle");
	jungleWork->setIdNum(1002);
	WorkModel *jungleModel = new WorkModel();
	jungleModel->setWorkModelName("Jungle_Model");
	jungleWork->setModel(jungleModel);

	//检查下是否改对了
	printf("\nSingle的作业:\n");
	singleWork->printWorkInfo();
	printf("\nJungle的作业:\n");
	jungleWork->printWorkInfo();

	system("pause");
	return 0;
}

效果如下图:

 5.原型模式总结

优点:

  • 当创建新的对象实例较为复杂时,原型模式可以简化创建过程,提高创建对象的效率;
  • 可扩展:模式中提供了抽象原型类,具体原型类可适当扩展;
  • 创建结构简单:创建工厂即为原型对象本身

缺点:

  • 深克隆代码较为复杂;
  • 每一个类都得配备一个clone方法,且该方法位于类的内部,修改时违背开闭原则;

适用环境:

  • 当创建新的对象实例较为复杂时,原型模式可以简化创建过程;
  • 结合优点第3条,需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少几个的组合状态,通过复制原型对象得到新实例,比通过使用构造函数创建一个新实例会更加方便。

设计模式系列文章:

设计模式——设计模式概述

设计模式(二)——UML类图介绍

设计模式(三)——面向对象设计原则

设计模式(四)——简单工厂模式

设计模式(五)——工厂方法模式

设计模式(六)——抽象工厂模式

设计模式(七)——建造者模式

源码和资料地址:https://github.com/FengJungle/DesignPattern


欢迎关注知乎专栏:Jungle是一个用Qt的工业Robot

欢迎关注Jungle的微信公众号:Jungle笔记

 

2018-04-22 17:02:27 fu123123fu 阅读数 78

介绍

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

浅复制

场景:我们都知道齐天大圣吹一根毫毛就可以变出一只猴子来,这只猴子跟齐天大圣长相一模一样。假定齐天大圣吹一根毫毛变出一只猴子A,这种以齐天大圣为原型,产生一只猴子A的过程就是原型模式。但是,出现了一个问题,猴子A和齐天大圣共用一根金箍棒,出现这种现象是因为这只是原型模式的浅拷贝。
代码:
1.先来描述一只猴子:

public class Monkey {
    private int height;
    private int weight;
    private Date birthday;
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

2.描述出齐天大圣的金箍棒:

public class JinGuBang implements Serializable{
    private float h=100;
    private float d=10;
    public void big(){
        this.h *= 2;
        this.d *= 2;
    }
    public void small(){
        this.h /= 2;
        this.d /= 2;
    }
}

3.描述出齐天大圣:

public class QiTianDaSheng extends Monkey implements Cloneable,Serializable{
    private JinGuBang jinGuBang=new JinGuBang();
    public QiTianDaSheng() {
        this.setBirthday(new Date());
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public JinGuBang getJinGuBang() {
        return jinGuBang;
    }
    public void setJinGuBang(JinGuBang jinGuBang) {
        this.jinGuBang = jinGuBang;
    }
}

4.浅拷贝测试结果:

public class SimpleTest {
    public static void main(String[] args) {
        //齐天大圣出来了
        QiTianDaSheng qiTianDaSheng=new QiTianDaSheng();
        try {
            //齐天大圣吹毫毛变出猴子A出来了
            QiTianDaSheng cloneA=(QiTianDaSheng)qiTianDaSheng.clone();
            //判断齐天大圣跟猴子A是不是同一个对象?答案:不是同一个,表明产生了新的对象
            System.out.println(qiTianDaSheng == cloneA);
            //判断齐天大圣的金箍棒跟猴子A的金箍棒是不是同一根?答案:是同一根金箍棒
            //原则上来说,齐天大圣跟猴子A应该各自都有一根金箍棒,而不应该共用同一根
            //说明这样的克隆是不完美的,这属于原型模式中的浅复制
            //如果猴子A让金箍棒变大一倍,那么齐天大圣的金箍棒就会跟着变大一倍
            System.out.println(qiTianDaSheng.getJinGuBang() == cloneA.getJinGuBang());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

再来看一个例子:
代码:
有一个普通对象Target1:

public class Target1 {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

再来一个普通对象Prototype1引用Target1:

public class Prototype1 implements Cloneable{
    private String name;
    private Target1 target1;
    private List list;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public List getList() {
        return list;
    }
    public void setList(List list) {
        this.list = list;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    public Target1 getTarget1() {
        return target1;
    }
    public void setTarget1(Target1 target1) {
        this.target1 = target1;
    }
}

观察p1(Prototype1)克隆出p2的过程:

/**
 * 有一个对象p1,它克隆出了对象p2
 * 然后,修改p2的list的值,p1的list的值也会跟着修改,说明他们用的是同一个引用,这是属于浅复制
 * 然后,修改p2的里一个引用Target1,p1里的引用Target1的值也会跟着变,这也是属于浅复制
 */
public class CloneTest1 {

    public static void main(String[] args) {
        //初始化p1
        Prototype1 p1=new Prototype1();
        p1.setName("张三");

        List list=new ArrayList();
        list.add("123");
        p1.setList(list);

        Target1 t1=new Target1();
        p1.setTarget1(t1);


        //根据p1复制一个p2
        try {
            Prototype1 p2=(Prototype1)p1.clone();
            p2.getList().add("234");
            p2.setName("李四");
            p2.getTarget1().setName("王五");

            System.out.println("p1======"+p1.getName());
            System.out.println("p1======"+p1.getList());
            System.out.println("p1======"+p1.getTarget1());
            System.out.println("p1======"+p1.getTarget1().getName());

            System.out.println("p2======"+p2.getName());
            System.out.println("p2======"+p2.getList());
            System.out.println("p2======"+p2.getTarget1());
            System.out.println("p2======"+p2.getTarget1().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }

    //执行结果:
    p1======张三
    p1======[123, 234]
    p1======com.taofut.sjms.prototype.simple1.Target1@1b6d3586
    p1======王五
    p2======李四
    p2======[123, 234]
    p2======com.taofut.sjms.prototype.simple1.Target1@1b6d3586
    p2======王五
    }
}

总结:直接实现java提供的Cloneable接口而不去重写它的话,这样实现的是一种浅复制,它能实现基本类型变量的值全部复制,但是不能实现类似集合,对象引用类型的复制,它仅仅是复制了对象的引用,该引用仍然还是指向原有对象,所以实际上还是只有一个对象,这样的话,就会造成新产生的对象自身做修改,还会影响到原有对象的变化,这是不安全的,所以这个原型模式是不完美的,属于浅复制。

深复制

场景:接着上面齐天大圣的案例,如果齐天大圣吹一根毫毛变出一只猴子A后,猴子A自身也拥有自己的金箍棒,那么这样的原型模式就完美了,它成功的复制出了一个一模一样的个体,但是这两者却又是不同的对象,齐天大圣还是齐天大圣,猴子A还是猴子A,它们只是长得一模一样,这样的复制属于深复制。
代码:
1.一样的,先来一只猴子:

public class Monkey {
    private int height;
    private int weight;
    private Date birthday;
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getWeight() {
        return weight;
    }
    public void setWeight(int weight) {
        this.weight = weight;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

2.再来一根金箍棒:

public class JinGuBang implements Serializable{
    private float h=100;
    private float d=10;
    public void big(){
        this.h *= 2;
        this.d *= 2;
    }
    public void small(){
        this.h /= 2;
        this.d /= 2;
    }
}

3.齐天大圣也该出来了:

public class QiTianDaSheng extends Monkey implements Cloneable,Serializable{
    private JinGuBang jinGuBang=new JinGuBang();
    public QiTianDaSheng() {
        this.setBirthday(new Date());
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
        return deepClone();//自己重写了该方法
    }
    public JinGuBang getJinGuBang() {
        return jinGuBang;
    }
    public void setJinGuBang(JinGuBang jinGuBang) {
        this.jinGuBang = jinGuBang;
    }
    /**
     * 序列化方式实现深度克隆(只是实现深度克隆的方式之一,反射也可以实现)
     * 把对象的字节码数组读出来,通过字节码数组重新构造一个新的对象
     * @return
     */
    public Object deepClone(){
        try {
            ByteArrayOutputStream bos=new ByteArrayOutputStream();
            ObjectOutputStream oos=new ObjectOutputStream(bos);
            oos.writeObject(this);

            ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois=new ObjectInputStream(bis);

            QiTianDaSheng cloneB=(QiTianDaSheng)ois.readObject();
            cloneB.setBirthday(new Date());
            return cloneB;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

总结:以上得到的就是对象类型完全一样,但又不是同一个对象的深复制模式,其实要实现深复制模式有多种方式,这里只是列举了序列化这一种,而spring中的原型模式基本用的都是反射。

2019-04-02 15:10:48 wuskzuo 阅读数 91

原型模式(Prototype Pattern)是 创建型模式 的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”,这个原型是可定制的。

适用场景

  1. 类初始化消耗资源较多
  2. new产生的对象需要比较繁琐的过程
  3. 构造函数比较复杂
  4. 循环体内产生大量的对象

简单克隆

创建基础ConcretePrototype,它实现了Prototypeclone()

public class ConcretePrototype implements Prototype {

    private int age;
    private List hobbis;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List getHobbis() {
        return hobbis;
    }

    public void setHobbis(List hobbis) {
        this.hobbis = hobbis;
    }

    @Override
    public Prototype clone() {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(this.age);
        concretePrototype.setHobbis(this.hobbis);
        return concretePrototype;
    }
}

创建测试类,查看复制结果。

public class Test {
    public static void main(String[] args) {
        ConcretePrototype concretePrototype = new ConcretePrototype();
        concretePrototype.setAge(15);
        List<String> list = new ArrayList<>();
        concretePrototype.setHobbis(list);
        ConcretePrototype concretePrototype1 = (ConcretePrototype) concretePrototype.clone();

        System.out.println("克隆对象引用地址"+(concretePrototype == concretePrototype1));
        System.out.println("克隆属性引用地址"+(concretePrototype.getHobbis() == concretePrototype1.getHobbis()));
    }
}


可以看出,我们确实复制了一个新的类。但是hobbies的应用地址却是相同的,意味着我们复制的并不是值,而是引用的地址。这就是我们常说的浅克隆

浅克隆
复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。
深克隆
复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

深克隆实现版


我们使用孙悟空的作为模型。猴哥猴哥,你真了不得,拔一根毫毛吹出猴万个,但是每只猴子都有个金箍棒,而这个金箍棒的复制应该就属于深克隆。接下来我们实现一下。
首先创建一个可序列化的金箍棒

public class Jingubang implements Serializable {

    public float h = 100;
    public float d = 10;
}

再创建一个悟空

public class Wukong implements Cloneable, Serializable {
    private int height;
    private int weight;
    private Jingubang jingubang;

    public Wukong() {
        this.height = 1;
        this.weight = 1;
        this.jingubang = new Jingubang();
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Jingubang getJingubang() {
        return jingubang;
    }

    public void setJingubang(Jingubang jingubang) {
        this.jingubang = jingubang;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return deepClone();
    }

    public Wukong deepClone(){

        try {
            ByteOutputStream byteOutputStream = new ByteOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteOutputStream);
            objectOutputStream.writeObject(this);

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);

            Wukong copy = (Wukong) objectInputStream.readObject();
            return copy;

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

使用序列化复制生成实例。

public class WukongTest {
    public static void main(String[] args) {
        Wukong sunweukong = new Wukong();

        Wukong liuermihou = null;
        try {
            liuermihou = (Wukong) sunweukong.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        System.out.println(sunweukong.getJingubang());
        System.out.println(liuermihou.getJingubang());
        System.out.println("克隆对象引用地址"+(sunweukong == liuermihou));
        System.out.println("克隆属性引用地址"+(sunweukong.getJingubang() == liuermihou.getJingubang()));

    }
}


由测试可以看出,我们复制生成的实例,已经完全是全新的实例了。

原型模式

阅读数 27

没有更多推荐了,返回首页