Java Object之clone()方法

2018-01-02  本文已影响0人  我不吃甜食

Object中的clone方法定义如下:
protected native Object clone() throws CloneNotSupportedException;

定义一个可克隆的对象,一般的步骤如下:

  1. implements Cloneable;
  2. override clone()
Example
//Person及其子类都有了克隆能力
class Person implements Cloneable {
        private int age;
        private String name;

        Person(int age, String name){
            this.age = age;
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public Object clone() {
            try {
                //实际调用了Object的clone()
                return super.clone();
            } catch (CloneNotSupportedException e){
                e.printStackTrace();
                return null;
            }
        }

        @Override
        public String toString() {
            return "Person{" +
                    "age=" + age +
                    ", name='" + name.hashCode() + '\'' +
                    '}';
        }
    }

如果调用Person personOfClone = person.clone(),实际上进行的是 shallow copy,即person和personOfClone中的name引用的是同一块内存地址。对personOfClone的修改可能会影响到person。那么如何进行 deep copy?若要实现 deep copy,则必须对对象内部的引用进行clone(前提是这些引用是可克隆的)直到所有的引用都进行了clone。

默认浅克隆是合理的,因为不能确定所有的引用都是可以克隆的。

通过序列化实现 deep copy
Example
public class Compete {
    public static final int SIZE = 25000;

    public static void main(String[] args) throws Exception {
        Thing2[] a = new Thing2[SIZE];
        for (int i = 0; i < a.length; i++)
            a[i] = new Thing2();
        long t1 = System.currentTimeMillis();
        ByteArrayOutputStream buf = new ByteArrayOutputStream();
        ObjectOutputStream o = new ObjectOutputStream(buf);
        for (int i = 0; i < a.length; i++)
            o.writeObject(a[i]);
        // Now get copies:
        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray()));

        Thing2[] c = new Thing2[SIZE];
        for (int i = 0; i < c.length; i++)
            //这里实际上已经进行了copy
            c[i] = (Thing2) in.readObject();
        long t2 = System.currentTimeMillis();
        System.out.println("Duplication via serialization: " +
                (t2 - t1) + " Milliseconds");

        //clone
        Thing4[] b = new Thing4[SIZE];
        for (int i = 0; i < b.length; i++)
            b[i] = new Thing4();

        t1 = System.currentTimeMillis();
        Thing4[] d = new Thing4[SIZE];
        for (int i = 0; i < d.length; i++)
            d[i] = (Thing4) b[i].clone();
        t2 = System.currentTimeMillis();
        System.out.println("Duplication via cloning: " +
                (t2 - t1) + " Milliseconds");
    }
    static class Thing1 implements Serializable {
    }

    static class Thing2 implements Serializable {
        Thing1 o1 = new Thing1();
    }

    static class Thing3 implements Cloneable {
        public Object clone() {
            Object o = null;
            try {
                o = super.clone();
            } catch (CloneNotSupportedException e) {
                System.err.println("Thing3 can't clone");
            }
            return o;
        }
    }

    static class Thing4 implements Cloneable {
        private Thing3 o3 = new Thing3();

        public Object clone() {
            Thing4 o = null;
            try {
                o = (Thing4) super.clone();
            } catch (CloneNotSupportedException e) {
                System.err.println("Thing4 can't clone");
            }
            // Clone the field, too:
            o.o3 = (Thing3) o3.clone();
            return o;
        }
    }
}

运行后发现,直接clone的速度要远快于序列化

控制克隆能力

上述例子中,一个对象首先要实现Cloneable对象,然后覆写clone()才能具有克隆能力,那么为何这样设计?

为何调用Object.clone()

调用Object.clone()时实际会发生什么,致使你重载clone()时必须要调用super.clone() 呢? 原因大概如下:

上一篇 下一篇

猜你喜欢

热点阅读