原型模式的理解
在java中我们知道通过new关键字创建的对象是非常繁琐的(类加载判断,内存分配,初始化等),在我们需要大量对象的情况下,原型模式就是我们可以考虑实现的方式。
原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深度克隆.
原型模式 | 说明 |
浅克隆 | 只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址 |
深度克隆 | 深复制把要复制的对象所引用的对象都复制了一遍 |
浅克隆
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
Object类提供的方法clone,只是拷贝本对象, 其对象内部的数组、引用对象等都不拷贝 ,还是指向原生对象的内部元素地址.被克隆的对象必须Cloneable,Serializable这两个接口;
package com.bobo.prototype; import java.io.Serializable; import java.util.Date; public class User implements Cloneable, Serializable { private String name; private Date birth; private int age; /** * 实现克隆的方法 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static void main(String[] args) throws Exception { // 创建一个普通对象 Date date = new Date(666666); User user = new User(); user.setName("波波烤鸭"); user.setAge(18); user.setBirth(date); System.out.println("原型对象的属性:" + user); // 克隆对象 User cloneUser = (User) user.clone(); System.out.println("克隆的对象的属性:" + cloneUser); // 修改原型对象的属性 date.setTime(12345677); // 修改克隆对象的属性 cloneUser.setName("波哥"); System.out.println("原型对象的属性:" + user); System.out.println("克隆的对象的属性:" + cloneUser); } @Override public String toString() { return "User{" + "name='" + name + ''' + ", birth=" + birth + ", age=" + age + '}'; } } 复制代码
输出结果
浅克隆的问题:虽然产生了两个完全不同的对象,但是被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深度克隆
被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。 实现的效果是:
深度克隆(deep clone)有两种实现方式,第一种是在浅克隆的基础上实现,第二种是通过序列化和反序列化实现,我们分别来介绍
方式一:在浅克隆的基础上实现
/** * 实现克隆的方法 * @return * @throws CloneNotSupportedException */ @Override protected Object clone() throws CloneNotSupportedException { User user = (User) super.clone(); // 实现深度克隆 user.birth = (Date) this.birth.clone(); return user; } 复制代码
方式二:序列化和反序列化
名称 | 说明 |
序列化 | 把对象转换为字节序列的过程。 |
反序列化 | 把字节序列恢复为对象的过程。 |
public static void main(String[] args) throws CloneNotSupportedException, Exception { Date date = new Date(1231231231231l); User user = new User(); user.setName("波波烤鸭"); user.setAge(18); user.setBirth(date); System.out.println("-----原型对象的属性------"); System.out.println(user); //使用序列化和反序列化实现深复制 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); }