Java 浅拷贝和深拷贝
一看就懂的,java深拷贝浅拷贝
1、直接赋值
- /* 建立类 */
- class Resume {
- private String name; //姓名
- private String sex; //性别
- private int age; //年龄
- private String experience; //工作经历
- public Resume(String name, String sex, int age) {
- this.name = name;
- this.sex = sex;
- this.age = age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public int getAge() {
- return age;
- }
- public void setExperience(String experience) {
- this.experience = experience;
- }
- public String getExperience() {
- return experience;
- }
- public void displayResume() {
- System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
- System.out.println("工作经历:"+experience);
- }
- }
- public class MainClass {
- public static void main(String[] args) {
- Resume zhangsan = new Resume("zhangsan","男",24);
- zhangsan.setExperience("2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制");
- zhangsan.displayResume();
- Resume zhangsan1 = zhangsan;
- zhangsan1.setExperience("2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等");
- zhangsan.displayResume();
- zhangsan1.displayResume();
- }
- }
程序运行结果
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码复制
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等
在本程序中,生成了一份zhangsan的简历。之后又复制了一份简历zhangsan1,可见zhangsan1中工作经历发生变化时,zhangsan的工作经历也发生了变化。
2、浅拷贝
- /* 建立类,实现Clone方法 */
- class Resume implements Cloneable{
- private String name; //姓名
- private String sex; //性别
- private int age; //年龄
- private String experience; //工作经历
- public Resume(String name, String sex, int age) {
- this.name = name;
- this.sex = sex;
- this.age = age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public int getAge() {
- return age;
- }
- public void setExperience(String experience) {
- this.experience = experience;
- }
- public String getExperience() {
- return experience;
- }
- public void displayResume() {
- System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
- System.out.println("工作经历:"+experience);
- }
- public Object clone() {
- try {
- return (Resume)super.clone();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- }
- public class MainClass {
- public static void main(String[] args) {
- Resume zhangsan = new Resume("zhangsan","男",24);
- zhangsan.setExperience("2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴");
- zhangsan.displayResume();
- Resume zhangsan1 = (Resume)zhangsan.clone();
- zhangsan1.setAge(23);
- zhangsan1.displayResume();
- Resume zhangsan2 = (Resume)zhangsan.clone();
- zhangsan2.setExperience("2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码");
- zhangsan2.displayResume();
- zhangsan.displayResume();
- }
- }
程序运行结果
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
- 姓名:zhangsan 性别:男 年龄:23
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学,精通JAVA,C,C++,C#等代码拷贝和粘贴
- class Experience {
- private String educationBackground;
- private String skills;
- public void setExperience(String educationBackground, String skills) {
- // TODO Auto-generated constructor stub
- this.educationBackground = educationBackground;
- this.skills = skills;
- }
- public String toString() {
- return educationBackground + skills;
- }
- }
- /* 建立类,实现Clone方法 */
- class Resume implements Cloneable{
- private String name; //姓名
- private String sex; //性别
- private int age; //年龄
- private Experience experience; //工作经历
- public Resume(String name, String sex, int age) {
- this.name = name;
- this.sex = sex;
- this.age = age;
- this.experience = new Experience();
- }
- public void setAge(int age) {
- this.age = age;
- }
- public int getAge() {
- return age;
- }
- public Experience getExperience() {
- return experience;
- }
- public void setExperience(String educationBackground, String skills) {
- experience.setExperience(educationBackground, skills);
- }
- public void displayResume() {
- System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
- System.out.println("工作经历:"+experience.toString());
- }
- public Object clone() {
- try {
- return (Resume)super.clone();
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- }
- public class MainClass {
- public static void main(String[] args) {
- Resume zhangsan = new Resume("zhangsan","男",24);
- zhangsan.setExperience("2009-2013就读于家里蹲大学","精通JAVA,C,C++,C#等代码拷贝和粘贴");
- zhangsan.displayResume();
- Resume zhangsan2 = (Resume)zhangsan.clone();
- zhangsan2.setExperience("2009-2013就读于家里蹲大学","精通JAVA,C,C++,C#等");
- zhangsan2.displayResume();
- zhangsan.displayResume();
- zhangsan2.displayResume();
- }
- }
程序运行结果:
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等代码拷贝和粘贴
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
- 姓名:zhangsan 性别:男 年龄:24
- 工作经历:2009-2013就读于家里蹲大学精通JAVA,C,C++,C#等
我们看一下上面两段程序差异在哪儿,第一段程序的工作经历是作为Resume类的一个普通的成员变量,也就是值属性。而后面一段程序中,工作经历Experience是一个类。结合上面程序的运行结果,我们再来理解“如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。”其实也就是说,zhangsan和zhangsan2里面的Experience类指向的是同一个对象嘛!那不管是zhangsan里面的Experience变化,还是zhangsan2里面的Experience变化都会影响另外一个啊。
3、深拷贝
其实出现问题的关键就在于clone()方法上,我们知道该clone()方法是使用Object类的clone()方法,但是该方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择性的拷贝,基本规则如下:
1、 基本类型
如果变量是基本很类型,则拷贝其值,比如int、float等。
2、 对象
如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。
3、 String字符串
若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有紫都城对象保持不变。
基于上面上面的规则,我们很容易发现问题的所在,他们三者公用一个对象,张三修改了该邮件内容,则李四和王五也会修改,所以才会出现上面的情况。对于这种情况我们还是可以解决的,只需要在clone()方法里面新建一个对象,然后张三引用该对象即可:
- rotected Person clone() {
- Person person = null;
- try {
- person = (Person) super.clone();
- person.setEmail(new Email(person.getEmail().getObject(),person.getEmail().getContent()));
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return person;
- }
所以:浅拷贝只是Java提供的一种简单的拷贝机制,不便于直接使用。
对于上面的解决方案还是存在一个问题,若我们系统中存在大量的对象是通过拷贝生成的,如果我们每一个类都写一个clone()方法,并将还需要进行深拷贝,新建大量的对象,这个工程是非常大的,这里我们可以利用序列化来实现对象的拷贝。
如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中,再从字节流中将其读出来,这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。
- public class CloneUtils {
- @SuppressWarnings("unchecked")
- public static <T extends Serializable> T clone(T obj){
- T cloneObj = null;
- try {
- //写入字节流
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ObjectOutputStream obs = new ObjectOutputStream(out);
- obs.writeObject(obj);
- obs.close();
- //分配内存,写入原始对象,生成新对象
- ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
- ObjectInputStream ois = new ObjectInputStream(ios);
- //返回生成的新对象
- cloneObj = (T) ois.readObject();
- ois.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- return cloneObj;
- }
- }
使用该工具类的对象必须要实现Serializable接口,否则是没有办法实现克隆的。
- public class Person implements Serializable{
- private static final long serialVersionUID = 2631590509760908280L;
- ..................
- //去除clone()方法
- }
- public class Email implements Serializable{
- private static final long serialVersionUID = 1267293988171991494L;
- ....................
- }
所以使用该工具类的对象只要实现Serializable接口就可实现对象的克隆,无须继承Cloneable接口实现clone()方法。
- public class Client {
- public static void main(String[] args) {
- //写封邮件
- Email email = new Email("请参加会议","请与今天12:30到二会议室参加会议...");
- Person person1 = new Person("张三",email);
- Person person2 = CloneUtils.clone(person1);
- person2.setName("李四");
- Person person3 = CloneUtils.clone(person1);
- person3.setName("王五");
- person1.getEmail().setContent("请与今天12:00到二会议室参加会议...");
- System.out.println(person1.getName() + "的邮件内容是:" + person1.getEmail().getContent());
- System.out.println(person2.getName() + "的邮件内容是:" + person2.getEmail().getContent());
- System.out.println(person3.getName() + "的邮件内容是:" + person3.getEmail().getContent());
- }
- }
- -------------------
- Output:
- 张三的邮件内容是:请与今天12:00到二会议室参加会议...
- 李四的邮件内容是:请与今天12:30到二会议室参加会议...
- 王五的邮件内容是:请与今天12:30到二会议室参加会议...
Java 浅拷贝和深拷贝的更多相关文章
- Java 浅拷贝、深拷贝,你知多少?
这是今天我们在技术群里面讨论的一个知识点,讨论的相当激烈,由于对这一块使用的比较少,所以对这一块多少有些盲区.这篇文章总结了所讨论的内容,希望这篇文章对你有所帮助. 在 Java 开发中,对象拷贝或者 ...
- Java 浅拷贝和深拷贝的理解和实现方式
Java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.举例说明:比如,对象A和对象B都属于类S,具有属性a和b.那么对对象A进行拷贝 ...
- java 浅拷贝和深拷贝 对象克隆clone
分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...
- 浅谈java浅拷贝和深拷贝
前言:深拷贝和浅拷贝的区别是什么? 浅拷贝:被复制的对象的所有变量都含有原来对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之, 浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象.深拷 ...
- 【转】Java 浅拷贝和深拷贝的理解和实现方式
Java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.举例说明:比如,对象A和对象B都属于类S,具有属性a和b.那么对对象A进行拷贝 ...
- Java 浅拷贝,深拷贝
从Java 强引用.软引用,弱引用http://blog.csdn.net/jltxgcy/article/details/35558465一文中,我们看到把一个对象赋值给另一个对象,本质上 ...
- java浅拷贝和深拷贝(基础也是很重要的)
对象的copy你兴许只是懵懂,或者是并没在意,来了解下吧. 对于的github基础代码https://github.com/chywx/JavaSE 最近学习c++,跟java很是相像,在慕课网学习c ...
- Java浅拷贝与深拷贝(思维导图)
图1 拷贝思维导图(点击查看图片) 1,拷贝 有两个相同属性的对象A和B,A拥有初始化值,将其值拷贝到B中,使得B拥有与A“相同”数据的属性!注意这里的相同我有加双引号! 相同可能表示这么几个意思:① ...
- java浅拷贝和深拷贝
转:http://blog.csdn.net/u014727260/article/details/55003402 实现clone的2点: 1,clone方法是Object类的一个方法,所以任何一个 ...
随机推荐
- scala 2.11.x/spec/03-types.md
scala/spec/03-types.md title: Types layout: default chapter: 3 --- Types Type ::= FunctionArgTypes ' ...
- Github远程推送一直Everything up-to-date
问题描述: Github远程推送一直Everything up-to-date,但其实并没有推送成功,远程库中没有更新文件 可能原因分析及解决方法: "git push with no ad ...
- Java作业五(2017-10-15)
/*3-6.程序员;龚猛*/ 1 package zhenshu; import java.util.Scanner; public class text { public static void m ...
- 深入理解Spring Redis的使用 (四)、RedisTemplate执行Redis脚本
对于Redis脚本使用过的同学都知道,这个主要是为了防止竞态条件而用的.因为脚本是顺序执行的.(不用担心效率问题)比如我在工作用,用来设置考试最高分. 如果还没有用过的话,先去看Redis脚本的介绍, ...
- [Swift]LeetCode447. 回旋镖的数量 | Number of Boomerangs
Given n points in the plane that are all pairwise distinct, a "boomerang" is a tuple of po ...
- GraphQL-前端开发的利剑与桥梁
GraphQL-前端开发的利剑与桥梁 基本概念 GraphQL GraphQL 是一种用于 API 的查询语言,由Facebook开发和开源,是使用基于类型系统来执行查询的服务端运行时(类型系统由你的 ...
- 如何看待Google欲回归中国事件
最近一条新闻刷爆了朋友圈: 8 月 6 日,<人民日报>在它位于 Facebook.Twitter 社交媒体平台的官方账号上发布了一篇标题为<Stability prerequisi ...
- 我要曝光!CDN 省钱大法!
七夕节刚过去,小明却特别郁闷,因为七夕当天,他错过了和远在北京的女神表白的机会.事情的经过是怎样的呢?为了在七夕当天送给自己女神一件礼物,小明在某购物网站上花重金购买了特别的礼物,礼物是从广东发送,结 ...
- 学习-xlsxwriter模块
Xlsx是python用来构造xlsx文件的模块,可以向excel2007+中写text,numbers,formulas 公式以及hyperlinks超链接. 可以完成xlsx文件的自动化构造,包括 ...
- linux安装字体方法
1.查看系统中文字体 #fc-list :lang=zh 2.如果提示commont not fount 说明为安装fontconfig 3.安装fontconfig #yum -y install ...