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方法}123456789101112131415161718192021测试类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());}1234567891011121314151617181920212223输出结果:----输出原型对象的属性------
org.zmf.User@1b6d3586zmfTue 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 1973123456789说明:克隆后的 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 方法}12345678910111213141516171819202122232425测试类: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());}
1234567891011121314151617181920212223测试结果:----输出原型对象的属性------
org.zmf.User2@1b6d3586zmfTue 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 2009123456789说明:根据测试得出克隆后的对象的属性并没有随着我们对原型对象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));}1234567891011121314151617181920212223242526272829303132测试结果:-----原型对象的属性------
org.zmf.User@1b6d3586zmfTue Jan 06 16:40:31 CST 2009Sat May 24 16:48:41 CST 8983------克隆对象的属性-------org.zmf.User@5f184fc6zmfTue Jan 06 16:40:31 CST 2009123456789实现了和第一种实现方式相同的效果~实现了深度克隆总结
实现对象克隆有两种方式:1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
---------------------