什么是原型模式
从一个对象再创建另外一个可定制对象,而且不需要知道创建的细节。
类似于僵尸母体,通过实现一个克隆的接口,将自身属性拷贝给其他僵尸,还可以进行基因突变。
拷贝方式分为
- 浅拷贝:仅仅复制所考虑的对象,而不复制它所引用的对象
- 深拷贝:将复制的对象引用的对象都复制一遍
浅拷贝
仅仅复制所考虑的对象,而不复制它所引用的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Zombie{ public String id; public Zombie cloneZombie() { Zombie z = new Zombie(); z.id = this.id; return z; } } public class Main{ public static void main(String[] args){ Zombie cz1 = new Zombie(); cz1.id="001"; Zombie cz2 = cz1.cloneZombie(); System.out.println((cz1==cz2)+":"+cz1.id+","+cz2.id); } }
|
深拷贝
将复制的对象引用的对象都复制一遍
java中自带的java.lang.Object.clone()分析
在研究原型模式的时候,我将接口中的拷贝方法命名为clone()
,却发现Java
内部已经有了一个clone()
方法。
1 2 3
| public class Object { protected native Object clone() throws CloneNotSupportedException; }
|
用native
修饰,表示是有JNI
实现,效率远高于非native
方法
用protected
修饰,表示要使用这个clone()
必须要继承自Object
类,Java
中所有类都是继承自Object
类。
返回Object
对象,表示需要强制类型转换。
Java对象中的clone
步骤
- 原型类实现
Cloneable
接口
- 重写
clone
方法,并调用super.clone()
方法
- 实现深拷贝
原型类实现Cloneable接口
ctrl+左键
查看源码发现,这是一个空的接口。
1 2
| public interface Cloneable { }
|
但是如果原型类没有实现Cloneable
接口而去调用Object.clone()
方法,会抛出CloneNotSupportedException
异常
重写clone方法,并调用super.clone()方法
继承自java.lang.Object.clone()
方法是浅拷贝。
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 33 34 35 36 37 38 39 40 41
| public class ZombieMSG { public String id; public String name; public ZombieMSG(String id, String name) { this.id = id; this.name = name; } public String toString(){ return "(id:"+id+",name:"+name+")"; } } public class Zombie implements Cloneable{ public String id; public ZombieMSG msg; public Zombie(String id,String name){ this.id = id; msg = new ZombieMSG(id, name); } public Object clone(){ Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } } public class Main{ public static void main(String[] args){ Zombie pz = new Zombie("000","母体僵尸"); System.out.println(pz.id+":"+pz.msg); Zombie cz1 = (Zombie) pz.clone(); cz1.id="001"; cz1.msg.id="001"; cz1.msg.name="普通僵尸1号"; System.out.println((pz==cz1)+"-"+pz.id+":"+pz.msg+","+cz1.id+":"+cz1.msg); } }
|
为什么我们在派生类中覆盖Object的clone()
方法时,一定要调用super.clone()
呢?
在运行时刻,Object
中的clone()
识别你要复制的是哪一个对象。
然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。
实现深拷贝
克隆类和被克隆类之间不应该存在引用传递的。也就是说。
普通僵尸肯定不能影响母体僵尸的,那么就要实现深拷贝。
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 33 34 35 36 37 38 39
| public class ZombieMSG implements Cloneable{ public Object clone(){ ZombieMSG obj = null; try { obj = (ZombieMSG) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } } public class Zombie implements Cloneable{ public Object clone(){ Zombie obj = null; try { obj = (Zombie) super.clone(); obj.msg = (ZombieMSG) this.msg.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } } public class Main{ public static void main(String[] args){ Zombie pz = new Zombie("000","母体僵尸"); System.out.println(pz.id+":"+pz.msg); Zombie cz1 = (Zombie) pz.clone(); cz1.id="001"; cz1.msg.id="001"; cz1.msg.name="普通僵尸1号"; System.out.println((pz==cz1)+"-"+pz.id+":"+pz.msg+","+cz1.id+":"+cz1.msg); } }
|