目录
一:原型模式的定义
二:关于深克隆和深克隆的区别
三:反序列化的方式实现深克隆
原型模式:
通过new产生一个对象需要非常繁琐的数据准备或访冋权限,则可以使用原型模式。
就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点
优势有:效率高(直接克隆,避免了重新执行构造过程步骤).
克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的对象的属性值完全和原型对象相同。并且克隆出的新对象改变不会影晌原型对象。然后,再修改克隆对象的值
原型模式实现:
继承Cloneable接囗和重写clone()方法
详解深克隆与浅克隆的区别示例:
打个比方,比如我们我们考试的时候,要抄别人的试卷,根据原型模式的思想,是没有必要从头到尾抄一遍的,而是把别人的试卷克隆一份,在这基础上进行修改就行了,而java给我们提供了clone()方法,让我们看看jdk里面的描述:
public interface Cloneable 一个类实现Cloneable接口,以指示Object.clone()方法,该方法对于该类的实例进行现场复制是合法的。 在不实现Cloneable接口的实例上调用对象的克隆方法导致抛出异常CloneNotSupportedException 。 按照惯例,实现此接口的类应使用公共方法覆盖Object.clone (受保护)。 |
因此,我们要用clone()方法,必须继承Cloneable接口!!!!!!!!
关于克隆,其实分别两类:
|
复制对象时仅仅复制对象本身,包括基本数据类型的属性,但该对象的属性为引用数据类型时,不会进行复制引用的对象,即拷贝出来的对象与被拷贝出来的对象中的属性引用的对象是同一个。 |
|
创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。 |
接下来,我将以试卷的克隆为例,实现一下clone()方法,并分析一下浅克隆和深克隆的区别~
- 首先创建一个试卷类test_paper继承Cloneable接口,然后我们就实现Object类的clone()方法,该类有两个私有属性,一个是姓名name(基本数据类型)、一个是日期date(引用数据类型),添加对应的构造器和set、get方法
package 四_原型模式;
import java.util.Date;
/**
* 克隆试卷
*/
public class test_paper implements Cloneable {
String name;//名字,基本数据类型
Date date;//日期,引用数据类型
//克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public test_paper() {}
public test_paper(String name, Date date) {
this.name = name;
this.date = date;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "test_paper{" +
"name='" + name + '\'' +
", date=" + date +
'}';
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
2. 然后我们在主函数里面进行测试
package 四_原型模式;
import java.util.Date;
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Date date = new Date();
String name = "zsr";
test_paper paper1 = new test_paper(name, date);
test_paper paper2 = (test_paper) paper1.clone();//通过paper1克隆出的对象
paper2.getDate().setDate(1000);
paper2.setName("gcc");
//如果修改paper2的引用类型(非基本数据类型)属性值,
//paper1的对应的引用类型属性值会跟着更改,因为这是浅克隆,克隆出的对象和元对象指向同一个属性
System.out.println(paper1);
System.out.println(paper2);
}
}
根据运行结果,我们发现正确克隆出了一张新的试卷,
- 我们修改克隆出的试卷的基本类型的属性name,原试卷对应的name属性并没有改变
- 但是我们修改克隆对象试卷的引用类型属性date,原试卷的date属性值跟着改变了,这就是浅复制
- 浅复制复制的时候复制了自己的本身,以及本身的基本类型的属性,但是对于自己的非基本数据类型的属性,并没有复制出一个新的相应的引用对象,即复制出来的对象与原对象中的非基本类型属性引用的对象是同一个!!所以对引用类型的属性进行修改,原对象和克隆对象对应的属性值都会改变!!!!!!
这样就没有达到完全复制、原对象和克隆对象相互之间完全没有影响的目的。那如果我们都想复制呢??那就引入了深复制~~
我们只需要在clone()方法中添加对应非基本类型属性的复制
在这个示例中,即加入对date属性的复制即可~
//克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
test_paper paper = (test_paper) super.clone();
paper.date = (Date) date.clone();
return paper;
}
根据我们新的实验结果,我们发现,修改paper2的所有属性值,对应的paper1元对象的属性值都不会改变,这就是深克隆,达到了元对象和克隆对象之间不会影响的效果!!
当然,实现深复制的方式可不止这么一种,我们还可以通过实现序列化和反序列化的方式实现深复制~
代码实现:
package 四_原型模式;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) throws Exception {
Date date = new Date();
String name = "zsr";
test_paper paper1 = new test_paper(name, date);
//通过序列化和反序列化来实现深克隆
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(bos);
obs.writeObject(paper1);
byte a[] = bos.toByteArray();
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(a));
test_paper paper3 = (test_paper) ois.readObject();//获取到新对象
paper3.getDate().setDate(1000);//改变非基本类型属性
System.out.println(paper1);
System.out.println(paper3);
}
}