深拷贝,浅拷贝,深克隆,浅克隆

深拷贝和浅拷贝:

浅拷贝只是拷贝对象的引用地址,两个引用地址指向的对象还是同一个,修改其中一个,另一个也会随之改变,因为这个引用地址指向的对象压根是同一个
而深拷贝是将对象和值都拷贝过来,形成一个新的对象,两者之间是独立的两个对象。在Java中,深拷贝又有两种实现形式:深克隆和浅克隆。

深克隆和浅克隆

浅克隆:实现Cloneable接口,重写clone()方法。

public class Hello implements Cloneable{
    String str="hello";
    public Object clone() {
        Object cloneObject=null;
        try {
            cloneObject=super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return cloneObject;
    }
}

 

浅克隆存在一个问题:只能克隆对象主体,不能克隆引用着的属性对象,两个对象的关联引用对象仍然是同一个,解决办法是将属性对象的类也实现Cloneable接口,重写clone()方法,当引用对象过多或出现嵌套引用时,这种方法特别操蛋。所以,《java核心技术卷》中不推荐这种克隆。
深克隆:实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下:

public class MyUtil {
    private MyUtil() {
        throw new AssertionError();
    }
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) 
                                  throws Exception {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bout);
        oos.writeObject(obj);
        ByteArrayInputStream bin = 
                    new ByteArrayInputStream(bout.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bin);
        return (T) ois.readObject();
        // 说明:调用ByteArrayInputStream
        //或ByteArrayOutputStream对象的close方法没有任何意义
        // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,
        //这一点不同于对外部资源(如文件流)的释放
    }
}

  

public static void main(String[] args) {
        try {
            Person p1 = new Person("郭靖", 33, 
                              new Car("Benz", 300));
            Person p2 = MyUtil.clone(p1);   // 深度克隆
            p2.getCar().setBrand("BYD");
            // 修改克隆的Person对象p2关联的汽车对象的品牌属性
            // 原来的Person对象p1关联的汽车不会受到任何影响
            // 因为在克隆Person对象时其关联的汽车对象也被克隆了
            System.out.println(p1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

  

posted @ 2020-05-08 17:45  codeFlyer  阅读(347)  评论(0编辑  收藏  举报