Java Clone

一,关于Java中的Clone

只要实现了Cloneable接口的类,其对象都可以调用clone()方法进行对象复制,如果没有实现Cloneable接口便掉clone方法会报CloneNotSupportedException。

值得注意的是,Cloneable接口并没有提供任何需要实现的方法,所以实现了Cloneable接口的类其意义只是声明了自己具有clone的功能。具体的clone实现是jdk底层实现了,对某对象调用clone方法后,向上遍历最终使用的是Object类的clone方法。示例:

public class Test implements Cloneable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Test(String name) {
        super();
        this.name = name;
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Test a = new Test("tom");
        Test b = (Test) a.clone();
    }
}

由于clone方法返回的类型是Object,所以clone后需要做一次类型转换。为了省事,可以在Test类中Override clone方法,在其中提供完成类型转换,这样在使用时不用再转了。如下:

public class Test implements Cloneable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Test(String name) {
        super();
        this.name = name;
    }

    @Override
    protected Test clone() throws CloneNotSupportedException {
        return (Test) super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        Test a = new Test("tom");
        Test b = a.clone();
    }
}

二,浅复制(Shallow Copy)

默认调用clone方法复制的对象,属于浅复制。也就是说原对象中的immutable属性的值会复制到新对象,但mutable属性将只复制引用到新对象。

  • immutable属性:比如String,int,float等基本数据类型属于Immutable属性
  • mutable属性:引用类型则为mutable属性。

浅复制会导致一个问题:由于引用类型的属性clone时,会将引用复制给新对象。所以新老对象的引用类型属性将指向同一片内存区域,一改皆改,不是个好事啊。如图:

三,深复制(Deep Copy)

由于上述浅复制的潜在问题,深复制需要不仅复制immutable属性的内容,还要将引用类型属性的内容也全盘复制过去,达到如下效果:

具体java示例如下:

public class ObjectABC implements Cloneable {
        public ObjectABC clone() throws CloneNotSupportedException {
                return (ObjectABC) super.clone();
        }
}

public class Z extends Y implements Cloneable{
        private ObjectABC someABC;

        public Z clone() throws CloneNotSupportedException {
                Z newZ = (Z) super.clone();
                newZ.someABC = someABC.clone();

                return newZ;
        }
}

public class test1 {
        public void function() throws CloneNotSupportedException {
                Y varY1 = new Z();
                Y varY2 = (Y) varY1.clone();
        }
}

四,问题

1,由于java clone需要遍历最终至Object类的clone方法来实现clone,所以类的继承层级太多会导致性能问题
2,浅克隆会导致引用类型属性值一改全改
3,深克隆又会导致递归问题(比如一个父子关系的类结构,当然这点弄的不是很清楚)

4.1解决办法

基于上面这些问题,尽量不要使用java的clone实现,

  • 深复制可使用:apache-commons SerializationUtils
  • 浅复制可以用:apache-commons BeanUtils