[b]原型模式[/b]
用原型的实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
在Java中使用原型模式需要实现 java.lang.Cloneable 接口。对于有些构造函数要执行很长时间的对象,在不需要改变初始化信息的情况下使用克隆可以大大的提高性能。
[quote="Java API文档"]
实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。
按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
Object.clone 方法执行的是“浅复制”而不是“深复制”操作。
[/quote]
Java的浅复制与深复制概念,这里首先要理解Java的另一个概念,传值与传引用
1) 浅复制
浅复制的对象变量都含有和原来对象相同的值(这里变量指基本类型的变量,String类也算),但那些引用其他对象的变量仍然指向原来的对象。
2) 深复制
深复制的对象变量都含有和原来对象相同的值,但那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
一个简单的浅复制代码事例,小狗复制成小猫
由此输出可见name与age字段都复制过来了,改变copy对象的值后source对象的值还是保持不变,但Pet对象中foods变量是一个List对象的引用,Object的clone方法是“浅复制”并没有复制变量引用的对象,因而copy对foods的修改就等于对source的修改。
要做到“深复制”在Java中有3种方式
1)所有对象都实现 java.lang.Cloneable 接口
2)利用Java的序列化和反序列化,要求所有对象都实现 java.io.Serializable 接口,如果有确实不可序列化的对象可使用 transient 关键字声明,从而将之排除在序列化之外
3)自己手动编码实现
用原型的实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
在Java中使用原型模式需要实现 java.lang.Cloneable 接口。对于有些构造函数要执行很长时间的对象,在不需要改变初始化信息的情况下使用克隆可以大大的提高性能。
[quote="Java API文档"]
实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常。
按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。
Object.clone 方法执行的是“浅复制”而不是“深复制”操作。
[/quote]
Java的浅复制与深复制概念,这里首先要理解Java的另一个概念,传值与传引用
1) 浅复制
浅复制的对象变量都含有和原来对象相同的值(这里变量指基本类型的变量,String类也算),但那些引用其他对象的变量仍然指向原来的对象。
2) 深复制
深复制的对象变量都含有和原来对象相同的值,但那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
一个简单的浅复制代码事例,小狗复制成小猫
public class Food {
public String name;
public Food(String name) {
this.name = name;
}
}
//实现 java.lang.Cloneable 接口
public class Pet implements Cloneable {
public String name;
public int age;
public List<Food> foods = new ArrayList<Food>();
public Pet(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Pet clone() {
Pet copy = null;
try {
copy = (Pet) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return copy;
}
}
public class Test {
public static void main(String[] args) {
Pet source = new Pet("小狗", 2);
source.foods.add(new Food("小狗爱吃狗粮"));
Pet copy = source.clone();
//修改前
System.out.println("-----------值修改前-----------");
System.out.println("source name: " + source.name);
System.out.println(" source age: " + source.age);
System.out.println("source food: " + source.foods.get(0).name);
System.out.println(" copy name: " + copy.name);
System.out.println(" copy age: " + copy.age);
System.out.println(" copy food: " + copy.foods.get(0).name);
System.out.println("-----------值修改后-----------");
copy.name = "小狗变小猫";
copy.age = 5;
copy.foods.get(0).name = "小猫要吃猫粮";
System.out.println("source name: " + source.name);
System.out.println(" source age: " + source.age);
System.out.println("source food: " + source.foods.get(0).name);
System.out.println(" copy name: " + copy.name);
System.out.println(" copy age: " + copy.age);
System.out.println(" copy food: " + copy.foods.get(0).name);
}
}
运行Test程序输出:
-----------值修改前-----------
source name: 小狗
source age: 2
source food: 小狗爱吃狗粮
copy name: 小狗
copy age: 2
copy food: 小狗爱吃狗粮
-----------值修改后-----------
source name: 小狗
source age: 2
source food: 小猫要吃猫粮
copy name: 小狗变小猫
copy age: 5
copy food: 小猫要吃猫粮
由此输出可见name与age字段都复制过来了,改变copy对象的值后source对象的值还是保持不变,但Pet对象中foods变量是一个List对象的引用,Object的clone方法是“浅复制”并没有复制变量引用的对象,因而copy对foods的修改就等于对source的修改。
要做到“深复制”在Java中有3种方式
1)所有对象都实现 java.lang.Cloneable 接口
2)利用Java的序列化和反序列化,要求所有对象都实现 java.io.Serializable 接口,如果有确实不可序列化的对象可使用 transient 关键字声明,从而将之排除在序列化之外
3)自己手动编码实现