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类的一个方法,所以任何一个 ...
随机推荐
- 记一次<iframe>的使用
将jsp拆分frame框架,因为采用了第一种方式,一直在考虑用jquery异步请求获取数据,总是但不到效果, 终于在js写吐的时候选择了第二种方式. //参考网上的使用,大多是下面这个样子,如果涉及静 ...
- ubuntu14.04 安装lnmp + redis
1.更新源 apt-get install update 2.安装nginx : apt-get install nginx 配置nginx: ① cd /etc/sites-enabled/ ② v ...
- Hibernate框架笔记04HQL_QBC查询详解_抓取策略优化机制
目录 1. Hibernate的查询方式 1.1 方式一:OID查询 1.2 方式二:对象导航查询 1.3 方式三:HQL方式 1.4 方式四:QBC查询 1.5 方式五:SQL查询 2. 环境搭建 ...
- 关于datagrid中数据条件颜色问题
前天公司考核中做了一个小的考核项目,在考核中一直没找到怎么设置datagrid中数据颜色的代码 他的题目是这样的: 项目资金小于50000时,项目资金数字需要红色文字显示,否则以绿色文字显示 后来找到 ...
- python之高阶函数和匿名函数
map() map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回. def func(x): return ...
- 3-4 计算属性的setter和getter
Vue中的计算属性的setter和getter //如上,fullName这个方法在取这个数据的时候,会执行get中的方法:而在设置数据时,会执行set中的方法.其中set中有个参数(value),用 ...
- Java 8中用法优雅的Stream,性能也"优雅"吗?
之前的文章中我们介绍了Java 8中Stream相关的API,我们提到Stream API可以极大提高Java程序员的生产力,让程序员写出高效率.干净.简洁的代码. 那么,Stream API的性能到 ...
- 使用C# (.NET Core) 实现抽象工厂设计模式 (Abstract Pattern)
本文的概念性内容来自深入浅出设计模式一书. 上一篇文章讲了简单工厂和工厂方法设计模式 http://www.cnblogs.com/cgzl/p/8760250.html, 使用的是披萨店的例子. 文 ...
- logback.xml sql语句输出
在使用springBoot框架之后,日志配置文件变成了logback.xml,输出sql语句的方法为: <!-- 打印sql语句 --> <logger name="com ...
- 强如 Disruptor 也发生内存溢出?
前言 OutOfMemoryError 问题相信很多朋友都遇到过,相对于常见的业务异常(数组越界.空指针等)来说这类问题是很难定位和解决的. 本文以最近碰到的一次线上内存溢出的定位.解决问题的方式展开 ...