简介: Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。 对于克隆(Clone),Java有一些限制: 1、被克隆的类必须自己实现Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。Cloneable 接口实际上是个标识接口,没有任何接口方法。 2、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。 3、在Java.lang.Object类中克隆方法是这么定义的: protected Object clone() throws CloneNotSupportedException 创建并返回此对象的一个副本。表明是一个受保护的方法,同一个包中可见。 按照惯例,返回的对象应该通过调用 super.clone 获得。 引题: 举个例子说吧,现在有一个对象比如叫foo,你需要在创建当前对象的一个副本作为存根你能怎么做? 假如你不用Clone,那么你可以先new一个对象foo1: Foo foo1=new Foo(), 然后用foo给foo1对象set值,这样就得到foo的副本foo1;除此之外,别无选择。 这样说,也许有人会觉得说的过于绝对了,不过事实如此啊。 要产生一个副本,那副本要不要内存?----当然要了,那就对了!既然需要内存,(不克隆的情况下)你不new还有什么办法呢?请大家时刻铭记对象是Java运行时产生的,驻留在计算机内存中。 常见错误: 下面我澄清几个初学者容易犯迷糊的错误,同样的问题,产生foo对象的副本: 1、Foo foo1=new Foo(); foo1=foo; 然后就想当然的认为副本foo1生成了! 错误原因:foo1没错是申请了内存,但是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo1、foo指向了同一内存区域。刚才new的操作制造一堆垃圾等着JVM回收。 2、Foo foo1=foo; 错误原因:还是两个变量都指向了同一块内存。 3、有些老鸟更厉害一些:在Foo中定义一个返回自身的方法: public Foo getInstance(){ return this; } 然后,Foo foo1=foo.getInstance(); 错误原因:同上,主要还是没有重新开辟内存,this在对象里是什么?----就是对象自己的引用!那么getInstance()自然返回的就是对象自己,反正又是两个对象穿了一条裤子----***,哈哈。错得心服口服吧。为了节省篇幅,我在最后写个例子,留给那些对此有异议的人看。 引入克隆 看了这么多方法都不行,还很麻烦!干脆用克隆吧,简单明了。 废话不说了,看例子: 定义两个类CloneFooA、CloneFooB,然后写个测试类CloneDemo分别克隆这两个类的对象,然后打印测试结果到控制台。 /** * Created by IntelliJ IDEA. * User: leizhimin * Date: 2007-9-20 * Time: 19:40:44 * 简单类克隆实现 * 要实现克隆,必须实现Cloneable接口,这是一个标识接口,没有接口方法 * 实现了 Cloneable 接口,以指示 Object.clone() 方法可以合法地对该类实例进行按字段复制。 * 按照惯例,实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的)。 */ public class CloneFooA implements Cloneable { private String strA; private int intA; public CloneFooA(String strA, int intA) { this.strA = strA; this.intA = intA; } public String getStrA() { return strA; } public void setStrA(String strA) { this.strA = strA; } public int getIntA() { return intA; } public void setIntA(int intA) { this.intA = intA; } /** * @return 创建并返回此对象的一个副本。 * @throws CloneNotSupportedException */ public Object clone() throws CloneNotSupportedException { //直接调用父类的clone()方法,返回克隆副本 return super.clone(); } } /** * Created by IntelliJ IDEA. * User: leizhimin * Date: 2007-9-20 * Time: 19:59:55 * 深度克隆对象,当类存在聚合关系的时候,克隆就必须考虑聚合对象的克隆 */ public class CloneFooB implements Cloneable { private CloneFooA fooA; private Double douB; public CloneFooB(Double douB) { this.douB = douB; } public CloneFooB(CloneFooA fooA, Double douB) { this.fooA = fooA; this.douB = douB; } public CloneFooA getFooA() { return fooA; } public void setFooA(CloneFooA fooA) { this.fooA = fooA; } public Double getDouB() { return douB; } public void setDouB(Double douB) { this.douB = douB; } /** * 克隆操作 * * @return 自身对象的一个副本 * @throws CloneNotSupportedException */ public Object clone() throws CloneNotSupportedException { //先调用父类的克隆方法进行克隆操作 CloneFooB cloneFooB = (CloneFooB) super.clone(); //对于克隆后出的对象cloneFooB,如果其成员fooA为null,则不能调用clone(),否则出空指针异常 if (this.fooA != null) cloneFooB.fooA = (CloneFooA) this.fooA.clone(); return cloneFooB; } } /** * Created by IntelliJ IDEA. * User: leizhimin * Date: 2007-9-20 * Time: 19:52:01 * 测试类:分别克隆CloneFooA和CloneFooB类,并打印克隆前后的结果. */ public class CloneDemo { public static void main(String args[]) throws CloneNotSupportedException { //CloneFooA克隆前 CloneFooA fooA1 = new CloneFooA("FooA", 11); System.out.println("CloneFooA的对象克隆前对象fooA1值为: " + fooA1.getStrA() + "," + fooA1.getIntA()); //CloneFooA克隆后 CloneFooA fooA2 = (CloneFooA) fooA1.clone(); System.out.println("CloneFooA的对象克隆后对象fooA2值为: " + fooA2.getStrA() + "," + fooA2.getIntA()); //比较fooA1和fooA2内存地址 if (fooA1 == fooA2) System.out.println("比较fooA1和fooA2内存地址:相等!"); else System.out.println("比较fooA1和fooA2内存地址:不相等!"); System.out.println("-------------------------"); //CloneFooB克隆前 CloneFooB fooB1 = new CloneFooB(fooA1, new Double("33")); System.out.println("CloneFooB的对象克隆前对象fooB1值为: " + fooB1.getFooA().getStrA() + "," + fooB1.getFooA().getIntA() + " | " + fooB1.getDouB()); //CloneFooB克隆后 CloneFooB fooB2 = (CloneFooB) fooB1.clone(); System.out.println("CloneFooB的对象克隆前对象fooB2值为: " + fooB2.getFooA().getStrA() + "," + fooB2.getFooA().getIntA() + " | " + fooB2.getDouB()); if (fooA1 == fooA2) System.out.println("比较fooB1和fooB2内存地址:相等!"); else System.out.println("比较fooB1和fooB2内存地址:不相等!"); } } 运行结果: CloneFooA的对象克隆前对象fooA1值为: FooA,11 CloneFooA的对象克隆后对象fooA2值为: FooA,11 比较fooA1和fooA2内存地址:不相等! ------------------------- CloneFooB的对象克隆前对象fooB1值为: FooA,11 | 33.0 CloneFooB的对象克隆前对象fooB2值为: FooA,11 | 33.0 比较fooB1和fooB2内存地址:不相等! Process finished with exit code 0 反面教材: 最后,我给出我上面提出到最后要给出的反面例子。 随便写一个,在CloneFooA 的基础上做了少许改动,内容如下: public class CloneFooA implements Cloneable { private String strA; private int intA; public CloneFooA(String strA, int intA) { this.strA = strA; this.intA = intA; } public String getStrA() { return strA; } public void setStrA(String strA) { this.strA = strA; } public int getIntA() { return intA; } public void setIntA(int intA) { this.intA = intA; } /** * @return 创建并返回此对象的一个副本。 * @throws CloneNotSupportedException */ public Object clone() throws CloneNotSupportedException { //直接调用父类的clone()方法,返回克隆副本 return super.clone(); } /** * @return 返回运行时的对象 */ public CloneFooA getInstance(){ return this; } public static void main(String args[]){ CloneFooA fooA=new CloneFooA("aa",11); System.out.println(fooA.getStrA()+" "+fooA.getIntA()); CloneFooA fooA1=fooA.getInstance(); System.out.println(fooA1.getStrA()+" "+fooA1.getIntA()); if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等!"); System.out.println("-------------------------"); //改变后fooA或者fooA1中任何一个,看看另外一个是否会改变 fooA1.setStrA("bb"); System.out.println(fooA.getStrA()+" "+fooA.getIntA()); System.out.println(fooA1.getStrA()+" "+fooA1.getIntA()); if(fooA==fooA1) System.out.println("fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了"); } } 运行结果: aa 11 aa 11 fooA和fooA1内存地址相等! ------------------------- bb 11 bb 11 fooA和fooA1内存地址相等,改变fooA1后,fooA的值也跟着变化了 Process finished with exit code 0
本文来自作者[翁淑慧]投稿,不代表泰博号立场,如若转载,请注明出处:https://www.staplesadv.cn/ds/21735.html
评论列表(3条)
我是泰博号的签约作者“翁淑慧”
本文概览:简介: Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。 对于克隆(Clone),Java有一些限制: 1、被克...
文章不错《面试题:简述object类9个方法的作用?》内容很有帮助