
Java常用设计模式之原型模式
内存中是这样的
实现深度克隆 其实也就是再我们重写clone()方法时,进行手动的克隆再返回。
发布日期:2021-05-07 08:16:29
浏览次数:32
分类:精选文章
本文共 4608 字,大约阅读时间需要 15 分钟。
原型模式
一、原型模式
Prototype模式是一种对象创建型模式,通过复制自己进行创建。
(一)、原型模式的特点
- 由原型对象自身创建目标对象,也就是说,对象创建这一动作发自原型对象本身。
- 目标对象是原型对象的一个克隆。通过Prottype模式创建的对象,不仅仅与目标对象具有相同的结构,还与目标对象具有相同的值
- 根据对象克隆深层次的不同,有浅度克隆与深度克隆
二、原型模式具体实现
(一)、克隆与复制的区别
克隆是指将一个对象复制出另一个对象信息相同的对象,并且他们的内存地址是不相同的,在堆中的对象信息相同但不是同一个;赋值只是改变了变量之间内存地址的指向。

(二)、如何实现克隆?
- 第一步:实现Cloneable接口
- 第二步:重写Object中的clone()方法
package 原型模式;// 第一步实现Cloneable接口public class Student implements Cloneable{ private int id; private String name; private String Sex; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return Sex; } public void setSex(String sex) { Sex = sex; }// 重写Object中的clone()方法 @Override protected Student clone() throws CloneNotSupportedException { return (Student) super.clone(); } }
调用一下,克隆是否成功?
package 原型模式;public class Maintest { public static void main(String[] args) { System.out.println(" 浅度克隆!"); Student s1 = new Student(); s1.setId(1); s1.setName("张三"); s1.setSex("男"); System.out.printf("S1指向内存地址:"+s1+"----"); System.out.println("S1信息:"+"\tid:"+s1.getId() +"\tname:"+s1.getName()+"\tsex"+s1.getSex()); /* 克隆s1 */ System.out.println("-----------------------------------------"); // s1要调用克隆方法 try { Student s2 = s1.clone(); System.out.printf("S2指向内存地址:"+s2+"----"); System.out.println("S2信息:"+"\tid:"+s2.getId() +"\tname:"+s2.getName()+"\tsex:"+s2.getSex()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}
**打印信息:**在打印信息中可以看S1和S2指向的内存地址是不同的,而两块内存地址所存储的信息是相同的,这就是克隆,而这只是浅度的克隆!浅度只能实现基本数据类型的克隆,而不能实现
深度克隆
通过上个案例我们看到了,浅度克隆的实现,克隆中也是区分层次的,浅度克隆只是针对基本数据类型的属性有效,对于复合数据类型就没有效果!通过案例来看一下,创建Student1对象添加一个数组属性,然后进行对象克隆,看一看数组的地址是否相同!
package 原型模式;import java.util.List;//第一步实现Cloneable接口public class Student1 implements Cloneable{ private String[] arr = new String[2]; public String[] getArr() { return arr; } public void setArr(String[] arr) { this.arr = arr; } // 重写Object中的clone()方法 @Override protected Student1 clone() throws CloneNotSupportedException { return (Student1) super.clone(); } }
package 原型模式;import java.util.ArrayList;import java.util.List;public class Test { public static void main(String[] args) { Student1 s1 = new Student1(); String[] arr = new String[2]; arr[0]="数组"; arr[1]="数据"; s1.setArr(arr); System.out.println("s1地址:"+s1); System.out.println("s1数组地址:"+s1.getArr()); System.out.println("存储信息:"+s1.getArr()[0]+"、"+s1.getArr()[1]); System.out.println("---------------------------------------------"); try { Student1 s2 = s1.clone(); System.out.println("s2地址:"+s2); System.out.println("s2-集合地址:"+s2.getArr()); System.out.println("存储信息:"+s2.getArr()[0]+"、"+s2.getArr()[1]); } catch (CloneNotSupportedException e) { e.printStackTrace(); }}}
打印后的结果:

package 原型模式;import java.util.List;//第一步实现Cloneable接口public class Student1 implements Cloneable{ private String[] arr = new String[2]; public String[] getArr() { return arr; } public void setArr(String[] arr) { this.arr = arr; } // 重写Object中的clone()方法 @Override protected Student1 clone() throws CloneNotSupportedException { // -------------------------实现深度克隆-----------------------// 先拿到克隆对象 Student1 student =(Student1)super.clone();// 然后进行手动克隆,自己进行循环赋值 // 先定义一个数组接受 String[] arr = new String[this.getArr().length];// 对拷 for(int i = 0; i < arr.length; i++) { arr[i] = this.getArr()[i]; } student.setArr(arr); return student;// --------------------------------------------------------- } }
package 原型模式;import java.util.ArrayList;import java.util.List;public class Test { public static void main(String[] args) { Student1 s1 = new Student1(); String[] arr = new String[2]; arr[0]="数组"; arr[1]="数据"; s1.setArr(arr); System.out.println("s1地址:"+s1); System.out.println("s1数组地址:"+s1.getArr()); System.out.println("存储信息:"+s1.getArr()[0]+"、"+s1.getArr()[1]); System.out.println("---------------------------------------------"); try { Student1 s2 = s1.clone(); System.out.println("s2地址:"+s2); System.out.println("s2-集合地址:"+s2.getArr()); System.out.println("存储信息:"+s2.getArr()[0]+"、"+s2.getArr()[1]); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }}
三、原型模式的优缺点
(一)、原型模式的优点
- 由于clone方法是有虚拟机直接复制内存块执行,所以在速度上比使用new的方式创建对象要快。
- 当创建的对象实例较为复杂的时候,使用原型模式可以简化对象创建的过程。
- 可以在运行时动态的获取对象的类型以及状态,从而创建一个对象
(二)、原型模式的缺点
- 需要为每个类配备一个克隆方法,而且该克隆方法位于这个类里面,当对已有的类进行改造时需要修改源代码,违背了开比原则
- 在实现深度克隆的时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用的时候,为了实现深度克隆,每一层对象的类都必须支持深度克隆,实现起来比较麻烦!
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月06日 22时02分48秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Unity平台 | 快速集成华为性能管理服务
2021-05-09
详细实例教程!集成华为虚假用户检测,防范虚假恶意流量
2021-05-09
对模拟器虚假设备识别能力提升15%!每日清理大师App集成系统完整性检测
2021-05-09
使用Power BI构建数据仓库与BI方案
2021-05-09
pytest封神之路第二步 132个命令行参数用法
2021-05-09
Django认证系统并不鸡肋反而很重要
2021-05-09
快用Django REST framework写写API吧
2021-05-09
tep用户手册帮你从unittest过渡到pytest
2021-05-09
12张图打开JMeter体系结构全局视角
2021-05-09
Spring Boot 2.x基础教程:构建RESTful API与单元测试
2021-05-09
[UWP 自定义控件]了解模板化控件(1):基础知识
2021-05-09
UWP 自定义控件:了解模板化控件 系列文章
2021-05-09
[UWP]从头开始创建并发布一个番茄钟
2021-05-09
在 Azure 上执行一些简单的 python 工作
2021-05-09
WinUI 3 Preview 3 发布了,再一次试试它的性能
2021-05-09
使用命令把SpringBoot项目打包成可运行的jar包(简洁,操作性强)
2021-05-09
List数组排序
2021-05-09
VMware vSphere 离线虚拟机安装 BIND 9
2021-05-09
说说第一份工作
2021-05-09
dojo/request模块整体架构解析
2021-05-09