java设计模式之原型模式-浅克隆与深克隆
《2019年阿里云双11活动拼团》:https://www.aliyun.com/1111/2019/group-buying-share
【限时】1年86元,3年229元,用来建站和编程学习【附WordPress建站教程】
定义:原型模式就是用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
在应用程序中,有些对象比较复杂,其创建过程过于复杂,而且我们又需要频繁的利用该对象,如果这个时候我们按照常规思维new该对象,那么务必会造成资源浪费,这个时候我们就希望可以利用一个已有的对象来不断对他进行复制就好了,这就是编程中的“克隆”。原型模式直接操作底层二进制流,在创建复杂对象是效率提升明显。
UML类图:
浅克隆与深克隆:
浅克隆:当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
深克隆:除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
浅克隆:
public class Person implements Cloneable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
Person dxy = (Person)gg.clone();
dxy.setName("dxy");
dxy.setGender(true);
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest{
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
`
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}
浅克隆对于引用类型,只克隆了引用,因此两个对象的interest公共同一个内存地址,一个对象变化,会引起另一个对象响应的变化。
深克隆:
public class Person implements Cloneable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone(); //直接调用object对象的clone()方法!
//添加如下代码实现深复制(deep Clone)
Person person = (Person) obj;
person.interest = (Interest)this.interest.clone(); //把属性也进行克隆!
return obj;
}
public static void main(String[] args) throws CloneNotSupportedException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
Person dxy = (Person)gg.clone();
dxy.setName("dxy");
dxy.setGender(true);
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest implements Cloneable {
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='dxy', gender=true, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
通过对引用类型值Interest添加clone方法,并且对Person对象的clone方法改造,实现深克隆。
此外还可以通过序列化和反序列化的方式实现深复制。
public class Person implements Serializable {
private String name;
private boolean gender;
private Interest interest;
public Person(String name, boolean gender, Interest interest) {
this.name = name;
this.gender = gender;
this.interest = interest;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
public Interest getInterest() {
return interest;
}
public void setInterest(Interest interest) {
this.interest = interest;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender=" + gender +
", interest=" + interest +
'}';
}
public static void main(String[] args) throws CloneNotSupportedException,ClassNotFoundException,IOException {
Interest interest = new Interest("摄影");
Person gg = new Person("gg",false,interest);
System.out.println(gg);
//使用序列化和反序列化实现深复制
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(gg);
byte[] bytes = bos.toByteArray();
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Person dxy = (Person) ois.readObject(); //克隆好的对象!
dxy.interest.setName("咖啡");
System.out.println(dxy);
System.out.println(gg);
}
}
class Interest implements Serializable{
private String name;
public Interest(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Interest{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
Person{name='gg', gender=false, interest=Interest{name='咖啡'}}
Person{name='gg', gender=false, interest=Interest{name='摄影'}}
`
优点:
当创建对象的实例较为复杂的时候,使用原型模式可以简化对象的创建过程。
直接操作二进制流,可以提高实例的创建效率。
缺点:
需要为每一个类配置一个克隆方法,而且该克隆方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违反了开闭原则。
在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重签到引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。
此外clone对象时,不调用构造方法,无视构造方法的权限。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)
2 回收无效对象的过程 当经可达性算法筛选出失效的对象之后,并不是立即清除,而是再给对象一次重生的机会 判断是否覆盖finalize() 未覆盖该或已调用过该方法,直接释放对象内存 已覆盖该方法且还未被执行,则将finalize()扔到F-Queue队列中 执行F-Queue中的finalize() 虚拟机会以较低的优先级执行这些finalize(),不会确保所有的finalize()都会执行结束 如果finalize()中出现耗时操作,虚拟机就直接停止执行,将该对象清除 对象重生或死亡 如果在执行finalize()方法时,将this赋给了某一个引用,则该对象重生 如果没有,那么就会被垃圾收集器清除 注意:强烈不建议使用finalize()进行任何操作!如果需要释放资源,请用try-finally或者其他方式都能做得更好. 因为finalize(
-
下一篇
阿里云服务器 Centos 7 如何搭建Java Web开发环境?
首选要有一台云服务器,开始部署开发环境,还没有购买的同学,请移至阿里云官网购买(记得领取代金券礼包,希望对你有所帮助!) 准备工作 安装目录 我们创建如下路径/usr/develop,然后在develop目录下面创建java,tomcat和mysql三个目录即可。 配置JDK 理解wget命令 wget命令是一个从网络上下载文件的自由工具,它支持http协议,https协议和ftp协议。因此我们可以通过wget命令来下载JDK。wget的格式:wget 要下载的url。下载的目录为当前执行wget命令的目录。 一.安装 JDK 1.首先查看一下系统是32位的还是64位的 执行: uname -m 2.去Oracle官网下载对应版本的JDK JDK下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 3.下载完后上传到云服务器,然后解压 tar -zxvf jdk-8u181-linux-x64.tar.gz4.将解压后的文件夹剪切到usr/local/jdk1....
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker容器配置,解决镜像无法拉取问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 2048小游戏-低调大师作品
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- MySQL数据库在高并发下的优化方案
- Dcoker安装(在线仓库),最新的服务器搭配容器使用
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题