继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【九月打卡】第14天+ 原型设计模式(创建型)

一起写代码2公众号
关注TA
已关注
手记 34
粉丝 1
获赞 5

课程名称:Java设计模式精讲 Debug方式+内存分析
课程章节:第9章 原型模式讲解+Coding+源码解析
主讲老师:Geely
课程内容:

问题1)定义

指原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象

不需要知道任何创建的细节,不用调用构造函数。

问题2)使用场景?

1、初始化消耗较多资源。

2,New 一个对象需要非常繁琐的过程(数据准备,访问权限等)

3,、构造函数比较复杂

4、循环体中产生大量对象。

问题3)优点和缺点?

优点:原型模式创建对象比直接new一个对象性能高。

简化创建过程

缺点:

1、必须配备克隆方法。(继承克隆接口(只是一个标识,它是可以备克隆的),重写object的克隆方法。)

  1. 对克隆复杂对象或克隆出的对象进行复制改造时,容易引入风险。

  2. 深拷贝、浅拷贝要运用得当。

问题4)克隆原型是实现方法?

第一步:实现Cloneable接口。(标识该类是可以被克隆的)

第二步:重写object类的clone方法。(clone方法默认是浅克隆)

第三步:深刻隆还是浅克隆,直接在clone方法中添加属性就可以。

public class pig implements Cloneable{

private String name;

private Date brithday;

  

public pig(String name,Date brithday){

this.name = name;

this.brithday = brithday;

}

  

public Date getBrithday() {

return brithday;

}

  

public void setBrithday(Date brithday) {

this.brithday = brithday;

}

  

public String getName() {

return name;

}

  

public void setName(String name) {

this.name = name;

}

  

@Override

public String toString() {

return "pig{" +

"name='" + name + '\'' +

", brithday=" + brithday +

'}'+super.toString();

}

  

@Override

protected Object clone() throws CloneNotSupportedException {

// 默认的浅克隆

// return super.clone();

//深克隆,就是将属性单独克隆。

pig pp = (pig)super.clone();

pp.brithday = (Date)pp.brithday.clone();

return pp;

}

}

  

public class test {

public static void main(String[] args) throws CloneNotSupportedException {

Date da = new Date(0L);

pig p1 = new pig("佩奇",da);

pig p2 = (pig) p1.clone();

System._out_.println("111111"+p1);

System._out_.println("222222"+p2);

  

p1.setName("小猪订单");

p1.setBrithday(new Date());

  

System._out_.println("111111"+p1);

System._out_.println("222222"+p2);

}

}

  

问题5)浅克隆和深克隆?

  1. 无论深克隆还是浅克隆,克隆出来的对象是和原来对象不是同一个地址。

  2. 浅克隆:共享原对象的非基本类型成员变量。(修改非基本成员变量,都会改变。)(基本成员变量不共享),浅克隆只是克隆基本类型成员变量,非基本类型成员变量是共享的。

  3. 深克隆:需要在clone方法中写上不同享的非基本成员变量。深克隆就是将非基本成员变量单独克隆。

1、浅克隆

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

在Java语言中,通过覆盖Object类的clone()方法可以实现浅克隆

2、深克隆

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

在Java语言中,如果需要实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式来实现。

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

序列化就是将对象写到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中。通过序列化实现的拷贝不仅可以复制对象本身,而且可以复制其引用的成员对象,因此通过序列化将对象写到一个流中,再从流里将其读出来,可以实现深克隆。需要注意的是能够实现序列化的对象其类必须实现Serializable接口,否则无法实现序列化操作。

扩展

Java语言提供的Cloneable接口和Serializable接口的代码非常简单,它们都是空接口,

这种空接口也称为标识接口,标识接口中没有任何方法的定义,

其作用是告诉JRE这些接口的实现类是否具有某个功能,如是否支持克隆、是否支持序列化等。

3,解决多层克隆问题:先序列化对象,然后再

如果引用类型里面还包含很多引用类型,或者内层引用类型的类里面又包含引用类型,使用clone方法就会很麻烦。这时我们可以用序列化的方式来实现对象的深克隆。

public class Outer implements Serializable {

private static final long _serialVersionUID_ = 369285298572941L;//最好是显式声明ID

public Inner inner;

  

//Discription:[深度复制方法,需要对象及对象所有的对象属性都实现序列化] 

public Outer myclone() {

Outer outer = null;

try {

// 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。

// 所以利用这个特性可以实现对象的深拷贝

**ByteArrayOutputStream baos =** **new** **ByteArrayOutputStream()****;**

**ObjectOutputStream oos =** **new** **ObjectOutputStream(baos)****;**

**oos.writeObject(****this****)****;**

// 将流序列化成对象

ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());

ObjectInputStream ois = new ObjectInputStream(bais);

outer = (Outer) ois.readObject();

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

return outer;

}

}

  

总结:

实现对象克隆有两种方式:

1).实现Cloneable接口并重写Object类中的clone()方法;

2).实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的

对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object

类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

问题6)如何防止克隆破坏单例模式?

方法1:防止克隆破坏单例,不实现Cloneable克隆接口。

方法2:防止克隆破坏单例模式。

即使实现了Cloneable克隆接口,可以在clone方法中。直接返回创建好的实例。而不是返回super.clone。

测试:通过反射,修改clone为public方法,然后再通过clone方法创建对象。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP