Java克隆(Clone)的应用

 

Java克隆(Clone)的应用
 
 
简介:
 
Java克隆(Clone)是Java语言的特性之一,但在实际中应用比较少见。但有时候用克隆会更方便更有效率。
 
对于克隆(Clone),Java有一些限制:
一、被克隆的类必须本身实现Cloneable 接口,以指示 Object.clone() 方法能够合法地对该类实例进行按字段复制。Cloneable 接口其实是个标识接口,没有任何接口方法。
二、实现Cloneable接口的类应该使用公共方法重写 Object.clone(它是受保护的)。某个对象实现了此接口就克隆它是不可能的。即便 clone 方法是反射性调用的,也没法保证它将得到成功。
三、在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对象的副本:
一、Foo foo1=new Foo();
   foo1=foo;
   而后就想固然的认为副本foo1生成了!
 
错误缘由:foo1没错是申请了内存,可是执行foo1=foo后,foo1就不在指向刚申请的内存区域了,转而指向foo对象的内存区域,这时候,foo一、foo指向了同一内存区域。刚才new的操做制造一堆垃圾等着JVM回收。
 
二、Foo foo1=foo;
错误缘由:仍是两个变量都指向了同一块内存。
 
三、有些老鸟更厉害一些:在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的值也跟着变化了
相关文章
相关标签/搜索