Java设计模式之原型模式
原型模式简介
原型模式实际上不算一种设计模式,应该说是一种技巧吧。当我们需要创建与已有对象一样的对象时,我们通常可以有两种容易想到的方法,一种是将已有对象指向另外一个重新创建的对象,如
//将old赋给new
Object newObject=oldObject;
原型模式在这种需求下就诞生了,我们知道Object乃一切对象的父类(超类),并且Object有一个原生的clone方法,但是该方法的调用必须要求类实现了Cloneable接口,虽然Cloneable接口只是一个摆设,里面空空荡荡,姑且就当Cloneable接口是clone方法实现的一个标志吧!我们可以创建一个类实现Cloneable即可,在覆写clone方法即可完成该类的克隆了。
原型模式的代码实现
下面写一个Dog类,该类实现了Cloneable接口,并且覆写了超类的clone方法,里面使用了super.clone,表示调用超类的原生代码即可。注意,Dog类有一个非基本数据类型的变量eye,下面会介绍这个点。
浅复制
package com.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Dog implements Cloneable,Serializable {
/**
*
*/
private static final long serialVersionUID = -2050795770781171788L;
private String name;
Eye eye;
public Dog(Eye eye) {
this.eye=eye;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Dog dog;
dog=(Dog) super.clone();
return dog;
}
}
class Eye implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2723012171722328322L;
String name;
public Eye(String name) {
this.name=name;
}
}
原型模式中的复制方法
在上面的原型模式代码中,我们覆写了clone方法,下面我们来进行一个测试:
测试代码一:
package com.prototype;
/**
* @author zzw922cn
*
*/
public class Test1 {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog(new Eye("红眼睛"));
dog.setName("狗一");
Dog object1 = (Dog) dog.clone();
object1.eye.name="绿眼睛";
object1.setName("狗二");
System.out.println(dog.eye.name);
System.out.println(object1.eye.name);
System.out.println(dog.getName());
System.out.println(object1.getName());
System.out.println(object1.equals(dog));
System.out.println(object1==dog);
System.out.println(object1.getClass().equals(dog.getClass()));
}
}
运行结果
绿眼睛
绿眼睛
狗一
狗二
false
false
true
这种clone一般称为浅复制,即并没有完全复制!
测试代码二
下面来进行一次深复制,即完全复制。我使用流的方式来进行深度复制,即完全拷贝。
深复制
package com.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Dog implements Cloneable,Serializable {
/**
*
*/
private static final long serialVersionUID = -2050795770781171788L;
private String name;
Eye eye;
public Dog(Eye eye) {
this.eye=eye;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Dog dog;
dog=(Dog) super.clone();
return dog;
}
/* 深复制 */
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
class Eye implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2723012171722328322L;
String name;
public Eye(String name) {
this.name=name;
}
}
接着写一个类似的测试代码
package com.prototype;
import java.io.IOException;
public class Test2 {
/**
* equal强调内容是否相同
* =强调地址是否相同
* @param args
* @throws CloneNotSupportedException
* @throws IOException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
Dog dog = new Dog(new Eye("红眼睛"));
dog.setName("狗一");
System.out.println("-----------------深复制--------------");
Dog object2 = (Dog) dog.deepClone();
object2.eye.name="绿眼睛";
object2.setName("狗二");
System.out.println(dog.eye.name);
System.out.println(object2.eye.name);
System.out.println(dog.getName());
System.out.println(object2.getName());
System.out.println(object2.equals(dog));
System.out.println(object2==dog);
System.out.println(object2.getClass().equals(dog.getClass()));
}
}
-----------------深复制--------------
红眼睛
绿眼睛
狗一
狗二
false
false
true
equals与==的区别
前面我们看到克隆对象与原始对象的equals和==都返回false,无论是浅复制还是深复制。那么equals和==到底是什么关系呢?
对于基本数据类型,==比较的是它们的值。而对于非基本类型的对象,==比较是它们在内存中的地址,如之前的oldObject与newObject二者的地址相同;而equals方法,如果它没有被子类覆写,它最原始的也是比较对象在内存中的地址,如果被子类覆写了,就不好说了。例如在String类型中,equals方法比较的是字符串的“表面值”,它并不是比较对象在内存中的地址,而==比较的是两个字符串在内存中的地址是否一样。例如String str1="Java",String str2=new String("Java");那么二者的关系是str1!=str2,str1.equals(str2)=true。原因是str1存在于字符串常量池中,str2存在于Java堆中,二者地址当然不同;但是二者的表面值是一样的,都是Java,因此equals方法返回true。
转载于:https://my.oschina.net/zzw922cn/blog/492044
上一篇: 男人养生该多吃什么
下一篇: 穿拖鞋也有禁忌 长期穿不利健康