Java常用设计模式————原型模式(二)之深拷贝与浅拷贝

引言

clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢? 

1 使用new操作符创建一个对象 

2 使用clone方法复制一个对象 

那么这两种方式有什么相同和不同呢? new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。而clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。【详解Java中的clone方法】

拷贝的种类

引用拷贝

package design.pattern.copy;
/*** 引用拷贝* <br>类名:CiteCopy<br>* 作者: mht<br>* 日期: 2018年4月1日-下午6:13:37<br>*/
public class CiteCopy {public static void main(String[] args) {Student s1 = new Student();Student s2 = s1;System.out.println(s1 + "\n" + s2);}
}

结果:

design.pattern.copy.Student@6d06d12f
design.pattern.copy.Student@6d06d12f


 

对象拷贝

 

package design.pattern.copy;
/*** 对象拷贝* <br>类名:Copy<br>* 作者: mht<br>* 日期: 2018年4月1日-下午6:13:37<br>*/
public class Copy {public static void main(String[] args) {Student s1 = new Student();Student s2 = (Student) s1.clone();System.out.println(s1 + "\n" + s2);}
}

结果:

design.pattern.copy.Student@15db9742
design.pattern.copy.Student@6d06d69c

浅拷贝

package design.pattern.copy;
/*** 浅拷贝* <br>类名:Copy<br>* 作者: mht<br>* 日期: 2018年4月1日-下午6:13:37<br>*/
public class Copy {public static void main(String[] args) {Student s1 = new Student();Teacher t1 = new Teacher();s1.setTeacher(t1);System.out.println("t1的内存地址:" + t1);Student s2 = (Student) s1.clone();// 两个学生对象的内存为:System.out.println(s1 + "\n" + s2);// 两个学生对象中的老师对象为:System.out.println(s1.getTeacher() + "\n" +  s2.getTeacher());}
}

结果:

t1的内存地址:design.pattern.copy.Teacher@15db9742
design.pattern.copy.Student@6d06d69c
design.pattern.copy.Student@7852e922
design.pattern.copy.Teacher@15db9742
design.pattern.copy.Teacher@15db9742

 

深拷贝

 

        通过clone方式实现的拷贝,默认是采用浅拷贝的方式,即只拷贝调用clone方法的对象,而对象内部引用的成员变量对象则不会一同进行复制,因此,就算是将内部的对象再进行clone拷贝,依然会出现内部对象的内部引用对象没有复制的问题。所以一般情况下,clone可以实现不彻底的深拷贝,无法实现彻底的深拷贝。

        通过Serializable实现深拷贝,会真正的实现整个对象的复制。

package design.pattern.copy;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 Student implements Serializable{private String name;private int age;private Teacher teacher;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Teacher getTeacher() {return teacher;}public void setTeacher(Teacher teacher) {this.teacher = teacher;}/*** 深拷贝* <br>作者: mht<br> * 时间:2018年4月1日-下午10:53:41<br>* @return*/protected Object deepClone(){try {// 序列化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();} catch (IOException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}
}
package design.pattern.copy;import java.io.Serializable;public class Teacher implements Serializable{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
package design.pattern.copy;
/*** Serializable序列化深拷贝* <br>类名:Copy<br>* 作者: mht<br>* 日期: 2018年4月1日-下午6:13:37<br>*/
public class Copy {public static void main(String[] args) {Student s1 = new Student();Teacher t1 = new Teacher();s1.setTeacher(t1);System.out.println("t1的内存地址:" + t1);System.out.println("==========================");Student s2 = (Student) s1.deepClone();// 两个学生对象的内存为:System.out.println(s1 + "\n" + s2);System.out.println("==========================");// 两个学生对象中的老师对象为:System.out.println("s1.getTeacher() : " + s1.getTeacher() + "\ns2.getTeacher() : " +  s2.getTeacher());}
}

结果:

t1的内存地址:design.pattern.copy.Teacher@15db9742
==========================
design.pattern.copy.Student@3d4eac69
design.pattern.copy.Student@232204a1
==========================
s1.getTeacher() : design.pattern.copy.Teacher@15db9742
s2.getTeacher() : design.pattern.copy.Teacher@4aa298b7

从上述结果可以看出,不仅student对象进行了复制,其s1内部的teacher对象也一同被复制了一个新的对象出来。但是要注意的是,Teacher类也一定要实现Serializable接口才可以,否则会产生NotSerializableException的运行时异常。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/559024.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java控制台输入教程~~~~

Java控制台输入教程~~~~当通过new Scanner&#xff08;System.in&#xff09;创建一个Scanner&#xff0c;控制台会一直等待输入&#xff0c;直到敲回车键结束&#xff0c;把所有输入的内容传给Scanner&#xff0c;作为扫描对象。如果要获取输入的内容&#xff0c;则只需要调用…

Java面试宝典————基础篇

参考原文&#xff1a;《Java面试题全集&#xff08;上&#xff09;》 1.Java中的基本数据类型有哪些&#xff1f; 类型&#xff1a;byte short int long float double boolean char 字节&#xff1a;1 2 4 8 4 8 1 2 2.面向…

Git初学札记(零)————EGIT完成Eclipse到GitHub一条龙

eclipse安装Egit插件 首先我们要找到所需的egit插件的url更新地址。百度一大堆&#xff0c;但是我还是希望自己去寻找。 打开Eclipse Downloads官网&#xff0c;在页面底部直接输入“egit”关键字&#xff0c;并直接点击第一条搜索到的结果。然后点击Downloads标签页&#xff0…

如何使用echo指令向文件写入内容

如何使用echo指令向文件写入内容0.前言本文总结如何使用echo命令向文件中写入内容&#xff0c;例如使用echo指令覆盖文件内容&#xff0c;使用echo指令向文件追加内容&#xff0c;使用echo指令往文件中追加制表符。echo向文件中输出内容的基本方法是使用IO重定向指令——“>…

Eclipse生成SSH传输密钥并实现GitHub的SSH代码提交

生成公私密钥 打开eclipse首选项完成如下操作&#xff1a;保存密钥&#xff1a;这里注意&#xff0c;博主之前已经生成过密钥了&#xff0c;因此这里只是演示截图&#xff0c;如果此时点击保存&#xff0c;会弹出“是否覆盖”提示框。 其中&#xff0c;id_rsa代表非对称加密算法…

Java实现链表结构

Java实现链表结构按链表的组织形式分有ArrayList和LinkList两种。ArrayList内部其实是用数组的形式实现链表&#xff0c;比较适合链表大小确定或较少对链表进行增删操作的情况&#xff0c;同时对每个链表节点的访问时间都是constant&#xff1b;而LinkList内部以一个List实现链…

SpringBoot————快速搭建springboot项目

完成项目的创建信息 浏览器打开SPRING INITIALIZR网址&#xff1a; http://start.spring.io/ 如下图所示完成配置&#xff1a; 1.完成基础项目配置 2.相关名称 3.依赖jar包&#xff0c;如果是web项目&#xff0c;那么这里选择的Web依赖已经包含了开发web项目所必须的服务器…

史上最容易理解————GET和POST两种基本请求方法的区别

GET和POST两种基本请求方法的区别GET和POST是HTTP请求的两种基本方法&#xff0c;要说它们的区别&#xff0c;接触过WEB开发的人都能说出一二。最直观的区别就是GET把参数包含在URL中&#xff0c;POST通过request body传递参数。你可能自己写过无数个GET和POST请求&#xff0c;…

SpringBoot————JPA快速使用

本篇博客源码地址&#xff1a;https://github.com/DragonWatcher/ease-run 概述 Hibernate与JPA 本篇博客中的web项目选用Hibernate作为持久层框架。在Spring Boot中&#xff0c;我们需要了解另一个概念&#xff1a;JPA 上一句话可能有些歧义&#xff0c;并不是说JPA就是Sp…

MySQL优化建议汇总~~~

MySQL优化建议汇总~~~1、将经常要用到的字段&#xff08;比如经常要用这些字段来排序&#xff0c;或者用来做搜索&#xff09;&#xff0c;则最好将这些字段设为索引 2、字段的种类尽可能用int或者tiny int类型。另外字段尽可能用not null 3、当然无可避免某些字段会用到text&a…

Java泛型初探————泛型通配

T ? K V E?——表示不确定的Java类型 T——表示Java类型 K、V——分别代表键-值中的Key-Value&#xff0c;例如Map<K,V>&#xff0c;put(K key, V value) E——代表Element&#xff0c;例如List<E>&#xff0c;add(E e)java.lang.ClassClass类的实例…

谈谈 final、finally、 finalize 有什么不同?

谈谈 final、finally、 finalize 有什么不同&#xff1f;final 可以用来修饰类、方法、变量&#xff0c;分别有不同的意义&#xff0c;final 修饰的 class 代表不可以继承扩展&#xff0c;final 的变量是不可以修改的&#xff0c;而 final 的方法也是不可以重写的&#xff08;o…

Spring Boot————静态方法如何调用Spring容器中的Bean

问题分析 在使用静态方法的时候&#xff0c;某些情况下&#xff0c;需要使用类似自动注入的Bean来实现某些业务逻辑。 一般的非静态方法&#xff0c;可以很容易的通过在方法所在的类中Autowired自动将依赖的Bean注入到本类中&#xff0c;并操作。 静态方法在使用同样的操作流…

Java 集合Collection常见知识点汇总~

看了一些所谓大公司的JAVA面试问题&#xff0c;发现对于JAVA集合类的使用都比较看重似的&#xff0c;而自己在这方面还真的是所真甚少&#xff0c;抽空也学习学习吧。 java.util包中包含了一系列重要的集合类&#xff0c;而对于集合类&#xff0c;主要需要掌握的就是它的内部结…

内部类详解————匿名内部类

内部类三连击&#xff1a; 《内部类详解————匿名内部类》 《内部类详解————局部内部类》 《内部类详解————静态嵌套类》 应用场景 由于匿名内部类不利于代码的重用&#xff0c;因此&#xff0c;一般在确定此内部类只会使用一次时&#xff0c;才会使用匿名内部…

内部类详解————局部内部类

内部类三连击&#xff1a; 《内部类详解————匿名内部类》 《内部类详解————局部内部类》 《内部类详解————静态嵌套类》 定义 在方法或某个作用域内的内部类&#xff0c;称为局部内部类。匿名内部类就是一种局部内部类。 实现方式 public class OutterType …

关于面向对象以及三大特征的解释

关于面向对象以及三大特征的解释面向对象&#xff1a;在C语言编程中是面向过程而在Java编程中是面向对象的。面向过程更重要的是看重实现的具体过程&#xff0c;面向对象看重的是结果&#xff0c;不管其里面的具体过程&#xff0c;只看结果。举一个例子&#xff1a;我们从住的地…

内部类详解————静态内部类

内部类三连击&#xff1a; 《内部类详解————匿名内部类》 《内部类详解————局部内部类》 《内部类详解————静态内部类》 定义 静态内部类&#xff0c;又叫静态嵌套类或嵌套类。是使用static关键字修饰的内部类。 静态内部类可以用 private 修饰&#xff0c;这…

jvm gc垃圾回收机制和参数说明amp;amp;Java JVM 垃圾回收(GC 在什么时候,对什么东西,做了什么事情)

jvm gc&#xff08;垃圾回收机制&#xff09; Java JVM 垃圾回收&#xff08;GC 在什么时候&#xff0c;对什么东西&#xff0c;做了什么事情&#xff09; 前言&#xff1a;&#xff08;先大概了解一下整个过程&#xff09;作者&#xff1a;知乎用户 链接&#xff1a;https:…

【Mathematical Model】Ransac线性回归Python代码

Ransac算法&#xff0c;也称为随机抽样一致性算法&#xff0c;是一种迭代方法&#xff0c;用于从一组包含噪声或异常值的数据中估计数学模型。Ransac算法特别适用于线性回归问题&#xff0c;因为它能够处理包含异常值的数据集&#xff0c;并能够估计出最佳的线性模型。 1 简介 …