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
输出结果:

----输出原型对象的属性------
[email protected]
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
[email protected]
知性人
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
测试结果:

----输出原型对象的属性------
[email protected]
zmf
Tue Jan 06 16:40:31 CST 2009
原型对象修改后的属性:Tue Nov 27 14:53:51 CST 1973
-------克隆对象的属性-----
[email protected]
知性人
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
测试结果:

-----原型对象的属性------
[email protected]
zmf
Tue Jan 06 16:40:31 CST 2009
Sat May 24 16:48:41 CST 8983
------克隆对象的属性-------
[email protected]
zmf
Tue Jan 06 16:40:31 CST 2009
1
2
3
4
5
6
7
8
9
实现了和第一种实现方式相同的效果~实现了深度克隆

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

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

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

原文地址:https://www.cnblogs.com/hyhy904/p/11082107.html

时间: 2024-11-05 04:51:50

Java 原型模式(克隆模式)的相关文章

原型模式(克隆模式)—浅谈浅克隆与深克隆

克隆是什么?它的产生背景? 当new的对象是多例的时候,new对象将会不断占据内存.特别是消耗内存的大对象,比如数据库连接等.平时运用的不多,只在spring等容器有见过,此处不多赘述,了解即可. 浅克隆与深克隆是什么意思?通过案例逐步探讨. public class Star implements Cloneable,Serializable{ private String name; private Date birthday; public Star(){} public Star(Str

Java原型模式(Prototype模式)

Prototype模式定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建. 如何使用原型模式 因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一下子变得很简单.以勺子为例: public abstract class Abstrac

基于原型机制的克隆模式

在传统的静态语言中,类相当于“模子”,用class来定义,而实例相当于“模具”,就是说实例是通过“模子”class来生成的.但是在js中,并没有class关键字,换句话说js中没有类的概念.但得益于js强大的原型机制,js是可以模拟静态语言中的类的. 先来看看函数对象Function,对象Function上拥有一个原型对象prototype,即 Function.prototype = { call:function(){}, apply:function(){}, ...... __proto

java设计模式5--原型模式(Prototype)

本文地址:http://www.cnblogs.com/archimedes/p/java-prototype-pattern.html,转载请注明源地址. 原型模式 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 概述 原型模式是从一个对象出发得到一个和自己有相同状态的新对象的成熟模式,该模式的关键是将一个对象定义为原型,并为其提供复制自己的方法. java.lang.Object类的clone方法 参见<java中的深浅克隆> 适用性 1.当一个系统应该独立于它的产品创建

java设计模式--创建型模式

2016-04-24 10:10:34 创建型模式:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 注意:工厂模式可以分为三类: 1)简单工厂模式(Simple Factory) 2)工厂方法模式(Factory Method) 3)抽象工厂模式(Abstract Factory)  这三种模式从上到下逐步抽象,并且更具一般性.GOF在<设计模式>一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory).将简单工厂模式

折腾Java设计模式之备忘录模式

原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's internal state allowing the object to be restored to this state later. 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态. 所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个

浅谈设计模式(二):装饰器模式|中介模式|原型模式

装饰器模式(Decorator Pattern) 装饰器模式可用来给一个类动态添加功能,将其装饰成一个新的类.这就是装饰器的概念.看到这里我们可能会想,要达到这种效果,我们用子类继承父类不就可以了吗? 没错装饰器模式,本身是一种继承的替代方案.那既然是替代方案,那么自然就有它不一样的地方. 具体区别在哪里呢? 请看 装饰器模式更灵活:继承时父子类的关系是静态的,而装饰器模式是动态的,装饰类和被装饰类的关系是运行时候确认的 装饰类和被装饰类的耦合关系是松散的,各自可以独立变化 下面看看具体的代码.

Horizon7发布完整克隆模式后,无法登录问题

问题描述:通过完整克隆模式发布后,发现,登录的时候无法使用域账户登录系统. 解决方法:后来发现自定义配置文件,没有设置自动加域,更改后重新发布即可.

Java设计模式(十) 备忘录模式 状态模式

(十九)备忘录模式 备忘录模式目的是保存一个对象的某个状态,在适当的时候恢复这个对象. class Memento{ private String value; public Memento(String value){ this.value = value; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } class Storage