JAVA对象克隆可能会出现的问题
首先,区分一下拷贝和克隆:
拷贝:当拷贝一个变量时,原始变量与拷贝变量引用的是同一个对象。当改变一个变量所引用的对象,则会对另一个变量造成影响。
克隆:当克隆一个对象时,是重新的创建了和该对象内容相同的对象。
clone方法是Object类受保护(preteced)方法,用户编写的代码不能直接调用。只有相同的类才能克隆其本身。
问题:
如果待克隆的对象中的所有数据域都是数值或基本类型,这样的克隆没有问题。
但是,如果在对象中包含了子对象的引用,拷贝的结果就会使得两个域引用同一个子对象,此时,原始对象和克隆对象将共享这一部分信息。
这样,当克隆对象改变这部分时,就会造成原始对象中数据的改变。
默认的克隆操作都是浅拷贝,它并没有克隆包含在对象中的内部对象。
进行浅拷贝会发生什么?
如果原始对象与浅克隆对象共享的子对象是不可变的,这样就不会产生问题。
但是,更多的情况是子对象是可变的。这样,就必须重写clone方法,以实现克隆子对象的深度拷贝。
对于待克隆的对象,需要作出一些判断:
(1)默认的克隆方法是否能够满足要求;
(2)默认的克隆方法是能够通过调用可变子对象的clone方法进行修补;
(3)是否不应该使用clone。
如果选1或2,类必须:
实现Cloneable接口,并使用public访问修饰符重新定义clone方法。
下面举例说明克隆机制:
import java.util.Date; import java.util.GregorianCalendar; public class TestClone { public static void main(String[] args) { try { /**原始对象**/ Employee origin = new Employee("Tom", 10000); origin.setHireDay(2014, 10, 10); /**克隆Employee对象**/ Employee copy = origin.clone(); copy.raiseSalary(10); copy.setHireDay(2015, 11, 11); System.err.println(origin); /**Tom,10000.0,Mon Nov 10 00:00:00 CST 2014**/ System.err.println(copy); /**Tom,11000.0,Fri Dec 11 00:00:00 CST 2015**/ /** * 可以看出数据域属于数值或基本类型时,克隆不会对其值造成影响, * 而类似Date这样的对象在进行克隆时就需要特别注意,必须进行深度克隆,将子对象也进行克隆 */ } catch (CloneNotSupportedException e) { e.printStackTrace(); } } } class Employee implements Cloneable { private String name; private double salary; private Date hireDay; public Employee(String n, double s) { this.name = n; this.salary = s; this.hireDay = new Date(); } public Employee clone() throws CloneNotSupportedException { /** 调用Object的clone方法 **/ Employee cloned = (Employee) super.clone(); /** 克隆可变的域对象 对可变的子对象进行克隆 **/ cloned.hireDay = (Date) hireDay.clone(); /**如果注释掉上面hireDay的克隆,最终将会得到如下结果,原始对象和克隆对象都指向同一个对象**/ /**Tom,10000.0,Fri Dec 11 00:00:00 CST 2015**/ /**Tom,11000.0,Fri Dec 11 00:00:00 CST 2015**/ return cloned; } public void setHireDay(int year, int month, int day) { Date newHireday = new GregorianCalendar(year, month, day).getTime(); hireDay.setTime(newHireday.getTime()); } public void raiseSalary(double byPrecent){ double raise = salary * byPrecent / 100; salary += raise; } /**重写Object类的toString方法**/ public String toString(){ return new StringBuffer().append(name).append(",").append(salary).append(",") .append(hireDay).toString(); } }
JAVA对象克隆可能会出现的问题的更多相关文章
- Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...
- (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨
原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- java对象克隆复制
原文链接:https://blog.csdn.net/ztchun/article/details/79110096 自己先简单描述总结一下:当想要将一个对象中已有的值直接给另外一个对象的时候,其实并 ...
- java对象克隆以及深拷贝和浅拷贝
1.什么是"克隆"? 在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能 会需要一个和A完全相同新对象B,并且此后对B任何改动都不 ...
- JAVA对象克隆
1> 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法. 2> 在派生类中覆盖基类的clone(),并声明为public.3> 在派生类的clone()方法中, ...
- Java提高篇——对象克隆(复制)
假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
- Java对象和集合的拷贝/克隆/复制
昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作.但是他对新的Bean操作后,会影响旧的Bean的值.当听到这个问题的时候,我第一反应就是他的拷贝方法 ...
随机推荐
- 解决com.fasterxml.jackson.databind.JsonMappingException: No suitable
原因:直接翻译,json格式,不匹配. 这原因坑爹啊,因为json格式不正确算一种原因. 还有一种就是接收的bean没有getter,setter方法. 最坑的一种就是数据无法被反序列化,list,m ...
- 解决Mysql数据库拒绝远程连接和忘记密码的问题
解决数据库忘记密码的问题 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) 编辑m ...
- Jenkins执行批处理文件、powershell失败
今天搭建Jenkins持续集成环境,编译环境是.net core.整理了一些发布的命令配置在Jenkins,问题来了,使用powershell插件运行dotnet restore.dotnet bui ...
- 通讯协议序列化解读(二) protostuff详解教程
上一篇文章 通讯协议序列化解读(一):http://www.cnblogs.com/tohxyblog/p/8974641.html 前言:上一面文章我们介绍了java序列化,以及谷歌protobu ...
- MySQL数据库优化的八种方式
引言: 关于数据库优化,网上有不少资料和方法,但是不少质量参差不齐,有些总结的不够到位,内容冗杂 偶尔发现了这篇文章,总结得很经典,文章流量也很大,所以拿到自己的总结文集中,积累优质文章,提升个人能力 ...
- MongoDB 数据库引用
MongoDB 引用有两种: 手动引用(Manual References) DBRefs DBRefs vs 手动引用 考虑这样的一个场景,我们在不同的集合中 (address_home, addr ...
- Gradle 1.12用户指南翻译——第四十九章. Build Dashboard 插件
本文由CSDN博客貌似掉线翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- tomcat内存溢出解决,java.lang.OutOfMemoryError: PermGen space
今天遇到了一个java.lang.OutOfMemoryError: PermGen space异常问题,一直解决不了,根据网上修改了tomcat的配置文件,但是还是解决不了,最后是通过如下方式解决的 ...
- Linux下文件和文件夹操作命令详解
花了两个小时的时间,把文件和文件夹相关的常用命令:创建.删除.移动.复制.查找.重命名在linux上测试了一把,总结下来.文件夹的这些基本操作是要多注意的,一不小心就达不到你想要的效果. 文件夹操作: ...
- [Python]查看python路径以及安装包的路径
特别是linux系统,装了多个python,有时候找不到python的绝对路径,有时候装了个django,又找不到django安装到哪里了..当然查看的方法有很多种,这里列出几种,供没有经验的人参考下 ...