JavaSE中深克隆和浅克隆

JavaSE中深克隆和浅克隆
2010-12-22 11:50

如何去理解深克隆和浅克隆呢?

首先从一个例子上来区分深克隆和浅克隆:

//MyObeject只是一个普通的类,下面的LocalCopy是对其的调用,关键是g(),f()两个//方法的区别

class MyObject implements Cloneable {

    int i;

    MyObject(int k) {

       i = k;

    }

    public Object clone() {

       Object o = null;

       try {

           o = super.clone();

       catch (CloneNotSupportedException e) {

           System.out.println("MyObject can't clone");

       }

       return o;

    }

    public String toString() {

       return Integer.toString(i);

    }

}

 

public class LocalCopy {

    static MyObject g(MyObject g) {

       g.i++;

       return g;

    }

    static MyObject f(MyObject f) {

       f = (MyObject) f.clone(); // Local copy

       f.i++;

       return f;

    }

    public static void main(String[] args) {

       MyObject a = new MyObject(11);

       System.out.println("a.i="+a.i);

       //以不同的方式获得了两个对象bc

       MyObject b = g(a);

       MyObject c = f(a);

       //bc的属性更改其值,看看对原对象a的属性的值有没有影响

       b.i=100;

       c.i=200;

       System.out.println("a.i="+a.i);

       System.out.println("b.i="+b.i);

        System.out.println("c.i="+c.i);  

       /*打印结果:

          a.i=11;

          a.i=100

        b.i=100

        c.i=200

         */

   }

    从表面上看,似乎会觉得a,b,c三个对象之间似乎没有什么联系,那么为什么同样的b对象和c对象对属性i值的修改后,结果a对象的值却改变的同b对象一样了,为什么不是c对象呢?实际上区别就在于b,c对象的获取方式不同,详细的解释请看下文:

【定义的区分】

浅克隆:就是只复制一个对象,而对象内部所存在的指向其他对象、数组或者引用则不予复制。

深克隆:相对于浅克隆,深克隆就不仅仅是复制一个对象那么简单,同时也会复制对象内部所包含的所有引用。

PS:改变浅克隆得到的对象(即引用)会影响对象本身的值和引用,而改变深克隆得到的对象则不会改变原来对象本身的值和引用(因为深克隆是对原对象进行了完全的按位复制,包括原对象的值和引用)。

 

    由上图可以看出浅克隆的对象和原对象共用所有的引用,而深克隆对象则已经与原来的对象没有任何关联性了,所以如果修改掉浅克隆的对象只有通过修改外面所引用的值来实现,这样的话,原来的对象的值也会发生改变,而深克隆对象值的改变则不会影响原来的对象了。

【实现方式】

关于克隆的一些概念:

通常新建一个类,它的基础类的类型是Object,而克隆方法是在所有类最基本的Object 中定义的,但克隆仍然不会在每个类里自动进行。那是为什么呢?那是因为在Object中的

clone()方法是protected模式的,这样是为了考虑到安全性而做出的设定的,如果设public的话,谁都可以克隆了,那就没有秘密可言了!基础类clone()提供了一个有用的功能——它进行的是对衍生类对象的真正“按位”复制,所以相当于标准的克隆行动。但是需要我们自己去覆盖这个clone()方法,并且将其设置为public的才能真正的实现克隆的效果。

一点小技巧:在判断对象是否实现了Cloneable,Serializable接口时可以采用instanceof来进行判定。

 

 

实现深克隆的方式主要有两种:

(1)   实现Cloneable接口,重写clone()方法;

(2)   通过一个对象序列化后在撤销对它的序列化,这个过程也可以实现克隆

PS:需要说明的是虽然这两个方法都可以实现深克隆,但是这两个方法也是是有区别的,主张还是使用第一种方法比较好,因为第二种方法实现起来的

    时间会比第一种方法多很多。

下面是对两种实现深克隆方式的例子的讲解:

(1)   实现Cloneable接口

      如上面的例子所示,MyObject类已经实现了深克隆方法,具体步骤如下:

         a.  实现Cloneable接口

         b.  Override重写clone()方法并且范围设置为public

         c.  调用clone()方法获得深克隆对象

2)将一个对象序列化以后再撤消对它的序列化,或者说进行装配,这个过程也是深克隆