JAVA浅拷贝与深拷贝简记

     clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象。所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。那么在java语言中,有几种方式可以创建对象呢? 
    1. 使用new操作符创建一个对象 
    2. 使用clone方法复制一个对象 
    那么这两种方式有什么相同和不同呢? new操作符的本意是分配内存。程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。而clone在第一步是和new相似的, 都是分配内存,调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域, 填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。【详解Java中的clone方法

    JAVA中有基本类型与引用类型,对象中属性可分为基本变量和引用变量,clone方法可复制基本变量的值,对于引用变量只会复制其引用(地址),原对象中引用变量值改变后,复制后对象内的引用变量值也会改变,因两者指向的地址相同,这就是平时所说的浅拷贝。Object类中默认clone方法为浅拷贝。    

    要想将对象引用变量也进行复制,需要进行深拷贝。    深拷贝的两种方式:

    一、逐层显示浅拷贝对象中的引用变量,直到最低层。

    被拷贝对象的类,包括引用变量中对象的类,需实现Cloneable接口,并覆写clone()方法,除调用父类中clone()方法外,还需将所有引用变量也进行clone,逐层浅拷贝。不足:逐层拷贝繁杂,若引用变量为第三方对象且其内还有引用变量,则无法进入到最低层。

    二,利用序列化与反序列化进行深拷贝。

    2.1 被拷贝对象及各级引用变量,实现Serializable接口,利用ByteArrayInputStream/ByteArrayOutputStream,
ObjectInputStream/ObjectOutputStream实现深拷贝。

     不过要注意,被transient修饰的属性就无法进行拷贝了。

//方式1
public static <T> T copyImplSerializable(T obj) throws Exception {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;

        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;

        Object o = null;
        //如果子类没有继承该接口,这一步会报错
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            bais = new ByteArrayInputStream(baos.toByteArray());
            ois = new ObjectInputStream(bais);

            o = ois.readObject();
            return (T) o;
        } catch (Exception e) {
            throw new Exception("对象中包含没有继承序列化的对象");
        } finally{
            try {
                baos.close();
                oos.close();
                bais.close();
                ois.close();
            } catch (Exception e2) {
                //这里报错不需要处理
            }
        }
    }

    2.2 将被拷贝对象转化为JSON,再由JSON转化为新对象

 public static <T> T copyByJson(T obj) throws Exception {
        //方式2
        Gson gson = new Gson();
        return (T) gson.fromJson(gson.toJson(obj), obj.getClass());
        //方式3
        //return (T) JSONObject.toBean(JSONObject.fromObject(obj),obj.getClass());
    }

以上代码来源:JAVA深层拷贝 - DeepCopy
简单测试: 对只有两个字符型属性的对象分别采用上述三种方式进行复制10000次,用时方式1约800ms,方式2约1000ms,方式3约1100ms ,用时好像没太大差别,可能是拷贝对象太小,其他方面的差异暂时未考量....

    

猜你喜欢

转载自blog.csdn.net/u012475575/article/details/80675925