
3.5 对象复制
假设我们需要对一个对象进行复制,怎么办呢?很多读者会想到赋值,例如:obj2=obj1。但是这个方法实际上并没有复制对象,而仅仅是建立一个新的对象引用,在执行这个操作后仍然只有一个对象,新建对象引用obj2也指向了对象引用obj1所指的对象。
本节介绍一个极其有用的方法Object.clone(),实现对象的复制。
既然clone是类Object中的一个方法,那么它能否像toString()这些方法一样,直接调用呢?我们来看下面这个例子。
例3.15 CloneDemo.java
class AnObject{ private int x; public AnObject(int x){ this.x =x; } public int getX(){ return x; } } public class CloneDemo{ public static void main(String args[]){ AnObject obj1 = new AnObject(100); AnObject obj2 = (AnObject)obj1.clone(); System.out.println("obj1 locate at "+obj1+" x="+obj1.getX()); System.out.println("obj2 locate at "+obj2+" x="+obj2.getX()); } }
上面的代码会引发编译错误。查阅Java API文档,我们会发现:Object.clone()是一个protected方法,因此不能直接调用clone()方法。我们将类AnObject修改如下:
class AnObject{ private int x; public AnObject(int x) { this.x =x; } public int getX(){ return x; } public Object clone(){ try{ return super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); return null; } } }
修改后的类AnObject定义了自己的clone()方法,它扩展Object.clone()方法。虽然CloneDemo.java可以编译,但是,当运行它时会抛出一个CloneNotSupportedException异常。通过阅读Java API文档我们发现,还必须让那些包含clone()方法的类实现Cloneable接口。代码如下:
class AnObject implements Cloneable{ private int x; public AnObject(int x){ this.x =x; } public int getX(){ return x; } public Object clone(){ try{ return super.clone(); }catch (CloneNotSupportedException e){ e.printStackTrace(); return null; } } }
再次编译并运行CloneDemo.java,得到:
obj1 locate at AnObject@182f0db x=100 obj2 locate at AnObject@192d342 x=100
观察运行结果,显然obj2复制了obj1,因为这两个对象中存储的x值均为100,并且位于内存中不同的位置。
由上面的程序可知,要使得一个类的对象具有复制能力,必须显式地定义clone()方法,并且该类必须实现Cloneable接口。Cloneable接口中没有定义任何内容,只是起“标记”的作用,说明类的设计者已经为该类设计了复制的功能(这一点与第4章将要讲到的接口有所不同)。如果类没有实现Cloneable接口,则在运行时会抛出一个CloneNotSupportedException异常。