原型模式
String类型有点特殊,它本身没有实现Cloneable接口,故根本无法克隆,只能传递引用。在clone()后,指向的值为常量。克隆出来的对象改变他的值,实际上是改变了克隆出来对象String类型成员的指向,不会影响被克隆对象的值及其指向。这样String在拷贝的时候就表现出了“深拷贝”的特点;实际上String作为不可更改的类(immutable class),在new赋值的时候,就已经创建了一个新的对象;
使用序列化深拷贝对象各个对象属性需要实现Serializable接口
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。本小结会通过对象的复制,进行讲解。在Java中,复制对象是通过clone()实现的,先创建一个原型类Person.java
public class Person implements Cloneable{
private String name;
private String sex;
private int age;
private List<String> friends;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
", friends=" + friends +
'}';
}
public List<String> getFriends() {
return friends;
}
public void setFriends(List<String> friends) {
this.friends = friends;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//克隆:浅克隆
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
//克隆:深克隆
public Person deepClone() {
try {
Person person = (Person) super.clone();
List<String> list = new ArrayList<>();
for(String s:this.getFriends()){
list.add(s);
}
person.setFriends(list);
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
另一个原型类:
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 */
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();
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
public SerializableObject getObj() {
return obj;
}
public void setObj(SerializableObject obj) {
this.obj = obj;
}
}
class SerializableObject implements Serializable {
private static final long serialVersionUID = 1L;
}
一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法,而在Object类中,clone()是native的,在这儿,我将结合对象的浅复制和深复制来说一下,首先需要了解对象深、浅复制的概念:
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
此处,写一个深浅复制的例子:原型实现Clonable接口,然后调用super.clone(); 然后原型中引用类型的属性需复制一份到新的Person类中。
//克隆:浅克隆
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
//克隆:深克隆
public Person deepClone() {
try {
Person person = (Person) super.clone();
List<String> list = new ArrayList<>();
for(String s:this.getFriends()){
list.add(s);
}
person.setFriends(list);
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
测试:
public static void main(String[] args) {
Person person1 = new Person();
person1.setName("zhangsan");
person1.setAge(30);
person1.setSex("男");
Person person2 = person1.clone();//克隆了一份Person
System.out.println(person1);
System.out.println(person2);
person1.setName("lisi");//person1的名称改了不影响person2的对象的名称,说明两个是不同的对象
System.out.println(person1);
System.out.println(person2);
System.out.println("*****************");
Person perso31 = new Person();
List<String> list = new ArrayList<>();
list.add("james");
list.add("yao");
perso31.setFriends(list);
System.out.println("********************");
Person person4 = perso31.deepClone();//深克隆后引用类型的属性不会再指向同一个对象
System.out.println(perso31);
System.out.println(person4);
System.out.println("********************");
list.add("Nike");
perso31.setFriends(list);
System.out.println(perso31);
System.out.println(person4);
}
输出:
Person{name='zhangsan', sex='男', age=30, friends=null}
Person{name='zhangsan', sex='男', age=30, friends=null}
Person{name='lisi', sex='男', age=30, friends=null}
Person{name='zhangsan', sex='男', age=30, friends=null}
*****************
********************
Person{name='null', sex='null', age=0, friends=[james, yao]}
Person{name='null', sex='null', age=0, friends=[james, yao]}
********************
Person{name='null', sex='null', age=0, friends=[james, yao, Nike]}
Person{name='null', sex='null', age=0, friends=[james, yao]}