深拷贝、浅拷贝与Cloneable接口

深拷贝与浅拷贝

浅拷贝

public class Student implements Cloneable{
    Integer a;
    Integer b;

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

    String c;
    Student child;
}

public class Main {

    public static void main(String[] args) throws CloneNotSupportedException {
        Student s = new Student();
        Student s2 = (Student) s.clone();
        System.out.println(s == s2);
        System.out.println(s.child == s2.child);
    }
}
/**********************************************************************/
false
true

由上述代码及运行结果我们可以看出,调用clone方法之后,确实s2是一个新的对象,内存地址已经发生了改变,但s和s2的child属性仍然指向相同的地址,这便是浅拷贝,当然8种基本数据类型是深拷贝,String则是例外。

深拷贝

public class Teacher implements Cloneable{
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}


public class Student implements Cloneable{
    Integer a;
    Integer b;

    public Student(Teacher t) {
        this.t = t;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Student s = (Student) super.clone();
        s.t = (Teacher)s.t.clone();//彻底深拷贝关键
        return s;
    }

    String c;
    Teacher t;
}


public class IntersectionofTwoArraysII {

    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher t = new Teacher();
        Student s = new Student(t);
        Student s2 = (Student) s.clone();
        System.out.println(s == s2);
        System.out.println(s.t == s2.t);
    }
}
/**********************************************************************/
false
false

如上代码运行结果所示为深拷贝,想要实现深拷贝,就需要在重写Cloneable接口的clone()方法,并调用属性的clone()方法,因此关联类也要实现Cloneable接口,从而形成拷贝链,实现彻底深拷贝
实现彻底的深拷贝并不容易,因为它要求涉及的所有类都实现了cloneable接口,但是如StringBuffer由于其没有实现Cloneable接口,想要实现深拷贝效果,则需要做特殊处理从而实现深拷贝的效果。可以在clone方法中实现
sb=new StringBuffer(sb.toString());

Cloneable接口

Cloneable其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现Cloneable其实就是一个标记接口接口,调用clone方法则会抛出CloneNotSupportedException(克隆不被支持)异常。

如何判断类是否实现了cloneable接口呢?

/**
     * Creates and returns a copy of this {@code Object}. The default
     * implementation returns a so-called "shallow" copy: It creates a new
     * instance of the same class and then copies the field values (including
     * object references) from this instance to the new instance. A "deep" copy,
     * in contrast, would also recursively clone nested objects. A subclass that
     * needs to implement this kind of cloning should call {@code super.clone()}
     * to create the new instance and then create deep copies of the nested,
     * mutable objects.
     *
     * @return a copy of this object.
     * @throws CloneNotSupportedException
     *             if this object's class does not implement the {@code
     *             Cloneable} interface.
     */
    protected Object clone() throws CloneNotSupportedException {
        if (!(this instanceof Cloneable)) {
            throw new CloneNotSupportedException("Class doesn't implement Cloneable");
        }
 
        return internalClone((Cloneable) this);
    }
 
    /*
     * Native helper method for cloning.
     */
    private native Object internalClone(Cloneable o);

clone方法首先会判对象是否实现了Cloneable接口,若无则抛出CloneNotSupportedException, 最后会调用internalClone. intervalClone是一个native方法,一般来说native方法的执行效率高于非native方法。

参考资料

详解Java中的clone方法 -- 原型模式

原文地址:https://www.cnblogs.com/wunsiang/p/12812723.html