锁定老帖子 主题:【解惑】小心浅克隆
精华帖 (0) :: 良好帖 (1) :: 新手帖 (11) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-07-19
最后修改:2010-06-18
★ Java对象赋值
Employee e1=new Employee("李"); //Employee是一个自定义类 Employee e2=e1; //赋值对象 e2.setName("王");//改变对象e2的名字 System.out.println(e1.getName()); //打印e1的结果: 王 Employee e1=new Employee("李"); //Employee是一个自定义类 Employee e2=e1; //赋值对象 e2.setName("王");//改变对象e2的名字 System.out.println(e1.getName()); //打印e1的结果: 王
这就是Java的对象赋值,改变e2的内容竟然会影响e1的内容。原因很简单,就是e1和e2这两个对象引用都指向了堆中同一个Employee类对象的内容。也就是说: Java的对象赋值的是引用(相当于C的指针)。如何让e1,e2成为内容相同的两个完全不同的对象呢,这就需要用到Java的对象克隆机制(将e2复制成e1的一个独立副本)。
★ Java对clone的支持
(1) 继承Object的clone方法的疑问? 有一点我们很清楚,Java的万类之祖Object中有一个clone()方法: protected native Object clone() throws CloneNotSupportedException 既然这个方法是protected的,显然是为了让子类能够使用。看看下面的代码: //Employee类中没有clone方法,也没有实现Cloneable接口 Employee original=new Employee("John Public"); Employee copy=original.clone(); //wrong //Employee类中没有clone方法,也没有实现Cloneable接口 Employee original=new Employee("John Public"); Employee copy=original.clone(); //wrong 有人会提出这样的疑问:不是所有的类都是Object的子类吗?不是所有的子类都可以访问受保护的方法吗 ? 毫无疑问,这两句提问没有任何错误。但是有一点必须搞清楚:你是否正真理解protected的作用范围呢?《【Java语言】你是否真正理解了protected的作用范围呢?》 。 (2) Java支持克隆 既然如此,难道我们就没有办法在某一个类的作用域外部来克隆这个类了吗? 答案是否定的! 我们可以在任何一个类中重写clone方法,并升级它的访问作用域。事实上,使用的时候也就是这样做的! 首先我们必须在需要克隆的类上实现一个重要的接口——Cloneable接口。这种接口我们叫作标记接口(tagging interface) 。这种标记接口没有任何方法,唯一的作用就是作为一个标志,用来告诉JVM一个类是否具有某个特定的功能。 如此一来,我们只要定义一个具有 Clone 功能的类就可以了: 1. 在类的声明中加入“ implements Cloneable ”,标志该类有克隆功能; class Employee implements Cloneable{ public Object clone() throws CloneNotSupportedException{//重载clone()方法 Employee cloned=(Employee)super.clone(); return cloned; } } class Employee implements Cloneable{ public Object clone() throws CloneNotSupportedException{//重载clone()方法 Employee cloned=(Employee)super.clone(); return cloned; } }
★ 深Clone和浅Clone
// 具备浅克隆的Employee类 class Employee implements Cloneable{ public String name=""; public Date hireDay=null; public Object clone(){ Employee cloned=(Employee)super.clone(); return cloned; } } Employee orignal=new Employee(); Employee copy=orignal.copy(); 对于上面的代码,克隆以后orignal与copy中的hireDay指向的是同样的存储位置。也就是说当我们调用copy.hireDay.setTime()方法后,orignal中的hireDay也会发生改变。但String类(由于常量池的存储方式)和基本数据类型变量时不会改变的。这种对子对象克隆无效的方式我们叫做浅克隆 。 很多情况下,我们需要将对象中的所有域(包括子对象)都进行真正的克隆。要做到这种深克隆,我们必须在重载clone()方法时克隆子对象: //具备深度克隆功能的Employee类 class Employee implement Cloneable{ public String name=""; private Date hireDay=null; public Object clone(){ Employee cloned=(Employee)super.clone(); //浅克隆 cloned.hireDay=(Date)hireDay.clone(); //克隆子对象 return cloned; } }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-04-18
不对啊..我试过了..那个原始对象的d 没有改变啊
import java.util.Date; public class CloneTest implements Cloneable{ private String s ; private Date d ; public void setD(Date d) { this.d = d; } public void setS(String s) { this.s = s; } public String say(){ return s + d ; } public Object clone(){ CloneTest cloned = null ; try { cloned = (CloneTest)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cloned; } public static void main(String[] args) { CloneTest clone = new CloneTest(); clone.setS("ssssssssssss") ; clone.setD(new Date()); for(int i =0;i<10000;i++){ } System.out.println( clone.say()); CloneTest clone2 = (CloneTest) clone.clone(); clone2.setS("sss"); clone2.setD(new Date()); System.out.println(clone.say()) ; System.out.println( clone2.say()) ; } } |
|
返回顶楼 | |
发表时间:2010-04-18
handleException 写道 不对啊..我试过了..那个原始对象的d 没有改变啊
import java.util.Date; public class CloneTest implements Cloneable{ private String s ; private Date d ; public void setD(Date d) { this.d = d; } public void setS(String s) { this.s = s; } public String say(){ return s + d ; } public Object clone(){ CloneTest cloned = null ; try { cloned = (CloneTest)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return cloned; } public static void main(String[] args) { CloneTest clone = new CloneTest(); clone.setS("ssssssssssss") ; clone.setD(new Date()); for(int i =0;i<10000;i++){ } System.out.println( clone.say()); CloneTest clone2 = (CloneTest) clone.clone(); clone2.setS("sss"); clone2.setD(new Date()); System.out.println(clone.say()) ; System.out.println( clone2.say()) ; } } 哥,一分钟之内是跑得完i从0到10000的,而且不同是值引用的对象不同。clone.getD()==clone2.getD()是false的。 |
|
返回顶楼 | |
发表时间:2010-04-19
for(int i =0;i<10000;i++){
} 你知道现代计算机对这样一个循环需要多久时间吗?连毫秒都显示不出来的。 循环100000000大概281ms左右 你的new Date()是没有什么不太一样的。换个别的对象试试 |
|
返回顶楼 | |
发表时间:2010-04-19
浅COPY bean的话可以用 BeanUtils.cloneBean方法..
深copy用对象串行化的方法吧 |
|
返回顶楼 | |
发表时间:2010-04-19
又复习了一遍基础知识,thks
|
|
返回顶楼 | |
发表时间:2010-05-06
最后修改:2010-05-06
深度克隆可以参考这个
http://www.iteye.com/topic/659877#1484197 |
|
返回顶楼 | |
浏览 4391 次