(五)原型模式 Prototype
原型模式目的是复制一个现有对象来生成新的对象,而不是通过实例化的方式。原型模式需要实现 Cloneable 接口,覆写clone方法,复制分为浅复制、深复制。
浅复制:将一个对象复制后,基本数据类型的变量都重新创建,引用类型,指向的还是原对象所指向的。
深复制:讲一个对象复制后,不论基本数据类型和引用类型,都是重新创建,是完全的彻底的复制。
public class ProtoType { public static void main(String[] args) throws Exception { Father f=new Father(); User u1=new User("123456",f); User u2=(User)u1.clone(); User u3=(User) u1.shallowClone(); System.out.println(u1==u2); //false System.out.println(u1.f==u2.f); //false System.out.println(u1.password == u2.password); //false System.out.println(u1.f==u3.f); //true System.out.println(u1.password == u3.password); //true } } class User implements Cloneable,Serializable{ String password; Father f; public User(String password,Father f){ this.password=password; this.f=f; } //浅复制 public Object shallowClone() throws CloneNotSupportedException{ User user = (User)super.clone(); return user; } //深复制 public Object clone() throws CloneNotSupportedException { //return super.clone(); ObjectOutputStream out=null; ObjectInputStream in=null; try { ByteArrayOutputStream bo = new ByteArrayOutputStream(); out = new ObjectOutputStream(bo); out.writeObject(this); out.flush(); byte[] bs = bo.toByteArray(); ByteArrayInputStream bi = new ByteArrayInputStream(bs); in = new ObjectInputStream(bi); Object o = in.readObject(); return o; } catch (IOException e) { e.printStackTrace(); return null; } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } finally{ try { out.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } } } } class Father implements Serializable{}原型模式与调用构造函数相比,复制创建的新对象会包含原始对象的某些状态,尤其当多个对象的类在属性上存在细微差别,方法完全相同时候。
浅复制与深复制还存在一个问题就是引用类型成本的问题。对于代码来说就是 Father 值的问题,上面的代码修改下。
class Father implements Serializable{ String name = "father"; } public static void main(String[] args) throws Exception { Father f = new Father(); User u1 = new User("123456",f); User u2 = (User)u1.clone(); User u3 = (User) u1.shallowClone(); u1.f.name = "aaaa"; System.out.println(u1.f.name); //aaaa 原型 System.out.println(u2.f.name); //father 深复制 System.out.println(u3.f.name); //aaaa 浅复制 }这样应该能跟深刻的理解了。