Java 原型模式(克隆模式)
Java 的设计模式有 23 种,前段时间小编已经介绍了单例模式,由于我们在学习 Spring 的时候在 bean 标签的学习中碰到了今天要讲的原型模式,那么小编就已本文来介绍下原型模式。
原型模式
  在java中我们知道通过new关键字创建的对象是非常繁琐的(类加载判断,内存分配,初始化等),在我们需要大量对象的情况下,原型模式就是我们可以考虑实现的方式。
  原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深度克隆
浅克隆
  在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。
简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
实现
被克隆的对象必须Cloneable,Serializable这两个接口
原型类
/**
 * 原型类:被克隆的类型
 */
public class User implements Cloneable, Serializable {
private String name;
private Date birth;
private int age;
/**
     * 实现克隆的方法
     * @return
     * @throws CloneNotSupportedException
     */
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    //此处略过get和set方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
测试类
public static void main(String[] args) throws CloneNotSupportedException {
    Date date =  new Date(1231231231231l);
    User user = new User();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("----输出原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
    // 克隆对象
    User user1 =(User) user.clone();
    // 修改原型对象中的属性
    date.setTime(123231231231l);
    System.out.println("原型对象修改后的属性:" + user.getBirth());
// 修改参数
    user1.setName("知性人");
    System.out.println("-------克隆对象的属性-----");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
输出结果:
----输出原型对象的属性------
org.zmf.User@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
org.zmf.User@14ae5a5
知性人
Tue Nov 27 14:53:51 CST 1973
1
2
3
4
5
6
7
8
9
说明:克隆后的 date 属性和原型对象修改后的 date 属性的结果一样 说明两个对象的Date的引用是同一个。由此可以说明,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。
深克隆
  在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。
简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。
深度克隆(deep clone)有两种实现方式,第一种是在浅克隆的基础上实现,第二种是通过序列化和反序列化实现,我们分别来介绍
1
第一种方式
在浅克隆的基础上实现
原型类
/**
 * 原型类:被克隆的类型
 * 深度克隆测试
 */
public class User2 implements Cloneable, Serializable {
private String name;
private Date birth;
private int age;
/**
     * 实现克隆的方法
     * 深度克隆(deep clone)
     */
    public Object clone() throws CloneNotSupportedException{
        Object object = super.clone();
        // 实现深度克隆(deep clone)
        User2 user = (User2)object;
        user.birth = (Date) this.birth.clone();
        return object;
    }
    //此处略过 get 和 set 方法
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
测试类:
public static void main(String[] args) throws CloneNotSupportedException {
    Date date =  new Date(1231231231231l);
    User2 user = new User2();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("----输出原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
    // 克隆对象
    User2 user1 =(User2) user.clone();
    // 修改原型对象中的属性
    date.setTime(123231231231l);
    System.out.println("原型对象修改后的属性:" + user.getBirth());
    // 修改参数
    user1.setName("知性人");
    System.out.println("-------克隆对象的属性-----");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
测试结果:
----输出原型对象的属性------
org.zmf.User2@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
org.zmf.User2@14ae5a5
知性人
Tue Jan 06 16:40:31 CST 2009
1
2
3
4
5
6
7
8
9
说明:根据测试得出克隆后的对象的属性并没有随着我们对原型对象Date属性的修改而改变,说明克隆对象的Date属性和原型对象的Date属性引用的不是同一个对象,实现的深度复制。
第二种方式:序列化和反序列化
说明
序列化:	把对象转换为字节序列的过程。
反序列化:	把字节序列恢复为对象的过程。
public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
    Date date =  new Date(1231231231231L);
    User user = new User();
    user.setName("zmf");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("-----原型对象的属性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
//使用序列化和反序列化实现深复制
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(user);
    byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
    ObjectInputStream ois = new ObjectInputStream(bis);
//克隆好的对象!
    User user1 = (User) ois.readObject();
// 修改原型对象的值
    date.setTime(221321321321321L);
    System.out.println(user.getBirth());
System.out.println("------克隆对象的属性-------");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth(http://www.my516.com));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
测试结果:
-----原型对象的属性------
org.zmf.User@1b6d3586
zmf
Tue Jan 06 16:40:31 CST 2009
Sat May 24 16:48:41 CST 8983
------克隆对象的属性-------
org.zmf.User@5f184fc6
zmf
Tue Jan 06 16:40:31 CST 2009
1
2
3
4
5
6
7
8
9
实现了和第一种实现方式相同的效果~实现了深度克隆
总结
实现对象克隆有两种方式:
1). 实现Cloneable接口并重写Object类中的clone()方法;
 2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
---------------------
Java 原型模式(克隆模式)的更多相关文章
- [19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)
		一.建造者模式 本质:分离了对象子组件的单独构造(由Builder负责)和装配的分离(由Director负责),从而可以构建出复杂的对象,这个模式适用于:某个对象的构建过程十分复杂 好处:由于构建和装 ... 
- Java原型模式
		原型模式 原型模式也称克隆模式.原型模式jian ming zhi yi,就是先创造出一个原型,然后通过类似于Java中的clone方法,对对象的拷贝,克隆类似于new,但是不同于new.new创造出 ... 
- JAVA 23种开发模式详解(代码举例)
		设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ... 
- java设计模式5--原型模式(Prototype)
		本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并 ... 
- java的23中设计模式
		一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ... 
- Java经典23创意模式设计模式(两)
		本文介绍5其余两种创意模式:模型构建器(Builder).原型模型(PROTOTYPE). 一.建造者模式(别名:生成者模式) 将复杂对象的构建和它的表示分离,使得相同的构建过程能够创建不同的表示. ... 
- 折腾Java设计模式之备忘录模式
		原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's int ... 
- java运行时内存模式学习
		学习java运行时内存模式: 各区介绍: 方法区(线程共享):用于存放被虚拟机加载的类的元数据:静态变量,常量,以及编译和的代码(字节码),也称为永久代(所有该类的实例被回收,或者此类classLoa ... 
- Java设计模式——装饰者模式
		JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ... 
随机推荐
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
			P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ... 
- Linux 之添加系统环境变量
			PATH 值是一系列目录,当执行命令时,linux就在这些目录下查找,其格式为: PATH=$PATH:<PATH1>:<PATH2>:<PATH3>:------ ... 
- window.onerror 捕捉所有的前端error
			//[捕捉所有前端error] window.onerror = function (errormessage, url, line, column, error) { console.log(&qu ... 
- ssm重新开发计科院新闻网站
			<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ... 
- 【转】PHP实现下载与压缩文件的封装与整理
			[转]PHP实现下载与压缩文件的封装与整理 https://mp.weixin.qq.com/s/BUI3QsdNi6Nqu0NhrUL8hQ 一.PHP实现打包zip并下载功能 $file_t ... 
- Linux运用一些常用命令
			今天搜集整理了一些Linux服务器运维常用命令,希望对大家有帮助:1.删除0字节文件 find -type f -size 0 -exec rm -rf {} 2.查看进程按内存从大到小排列 ps - ... 
- uoj#279. 【UTR #2】题目交流通道(容斥+数数)
			传送门 先考虑无解的情况,为以下几种:\(dis_{i,j}+dis_{j,k}<dis_{i,k}\),\(dis_{i,i}\neq 0\),\(dis_{i,j}\neq dis_{j,i ... 
- 关于c语言中的字符串的问题
			静态数组,动态数组,链表是c语言中处理存储数据最基本的三种方式. 1.静态数组,你先定好大小,直接赋值即可,不要超过定义的长度. 2.动态分配数组,在执行的时候,输入要分的内存大小,然后p=(vo ... 
- IT兄弟连 Java语法教程 Java语言背景
			驱使计算机语言革新的因素有两个:程序设计技术的改进和计算环境的改变.Java也不例外.在大量继承C和C++的基础之上,Java还增加了反应当前程序设计技术状态的功能与精华.针对在线环境的蓬勃发展(In ... 
- python3 安装虚拟镜像
			virtualenvwrapper--提供了一系列命令使得和虚拟环境工作变得愉快很多,他把你所需要的虚拟环境都放在一个地方. 1.先安装virtualenv:pip install virtualen ... 
