Java的深拷贝与浅拷贝

2020-04-28  本文已影响0人  Responsibility_

在学习C++时,老师说过值传递引用传递。Java中只有值传递。今天我们就来讨论一下什么是浅拷贝与深拷贝。
先写一个例子给大家:
创建一个消费者类,其中包含属性,构造方法与get set方法.

public class Buyer {
    String name;
    int Level;
    char sex;
    double price;
    
    public Buyer(String name,int level, char sex, double price) {
        this.name = name;
        this.Level = level;
        this.sex = sex;
        this.price = price;
    }

对这个类进行创建工作:

public class BuyeTest {
    public static void main(String[] args) {
        Buyer buyter1 = new Buyer("小张",13,'男',100.3);
        Buyer buyter2 = buyter1;
        buyter1.setLevel(10);
                //打印两个对象
        System.out.println(buyter1);
        System.out.println(buyter2);
    }
}
image.png

结果在我们意料之内,只创建了一个对象,两个变量同时指向同一个地址,所以一改全改.
那有什么办法能够不创建对象,然而得到多个独立的对象呢?答案是有的,那就是拷贝.在实现拷贝之前要实现一个接口:


image.png

在object类中有clone()方法,我们只需要在子类中调用clone()方法即可,那么我们来试一试。


调用父类的clone方法

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

再次使用clone方法拷贝对象

public class BuyeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Buyer buyter1 = new Buyer("小张",13,'男',100.3);
        Buyer buyter2 = (Buyer) buyter1.clone();
        buyter1.setLevel(10);
        System.out.println(buyter1);
        System.out.println(buyter2);
    }
}

结果:


image.png

符合预期效果,浅拷贝完成,为什么说他是浅拷贝呢?已经是两个独立的对象了呀?其实并不是。

浅拷贝
public class Product {
    String name;
    double proPrice;

    public Product(String name, double proPrice) {
        this.name = name;
        this.proPrice = proPrice;
    }
}
public class Buyer implements Cloneable{
    String name;
    int Level;
    char sex;
    double price;
    Product product;
    
    public Buyer(String name,int level, char sex, double price,Product product) {
        this.name = name;
        this.Level = level;
        this.sex = sex;
        this.price = price;
        this.product = product;
    }
}
用同样方法进行复制对象:
public class BuyeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建Product类
        Product product = new Product("饼干", 15.3);
        Buyer buyter1 = new Buyer("小张", 13, '男', 100.3, product);
        Buyer buyter2 = (Buyer) buyter1.clone();
        buyter1.getProduct().setName("蛋糕");
        System.out.println(buyter1);
        System.out.println(buyter2);
    }
}
image.png

修改了其中一个对象的值,另一个也随之改变,并非完全独立.


使用深拷贝来解决这个问题:

@Override
    public String toString() {
        return "Product [name=" + name + ", proPrice=" + proPrice + "]";
    }

Buyer类中重写clone方法

@Override
    protected Object clone() throws CloneNotSupportedException {
        Buyer buyter = (Buyer)super.clone();
        Product product  = (Product)buyter.getProduct().clone();
        buyter.setProduct(product);
        return buyter;
    }

再次运行结果


image.png

方法1 能够解决问题,但是一旦遇到复杂的对象,递归遍历对象图就会消耗大量时间空间.


    //方法2
    protected Object deepClone() throws Exception {
//      将Buyer转换为字节流(序列化)
        ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 字节数组输出流
        ObjectOutputStream oos = new ObjectOutputStream(bos); // 对象输出流(用于实现序列化)
        oos.writeObject(this);

        // 将字节流转换为新的Buyer(反序列化)
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); // 创建字节数组输入流,传入"序列化后的字节流"
        ObjectInputStream ois = new ObjectInputStream(bis); // 对象输入流(用于实现反序列化)
        Buyer buyer = (Buyer) ois.readObject();
        return buyer;

    }

测试

public static void main(String[] args) throws Exception {
        // 创建Product类
        Product product = new Product("饼干", 15.3);
        Buyer buyter1 = new Buyer("小张", 13, '男', 100.3, product);
//      Buyer buyter2 = (Buyer) buyter1.clone();
//      buyter1.getProduct().setName("蛋糕");
//      System.out.println(buyter1);
//      System.out.println(buyter2);
        Buyer buyter3 = (Buyer) buyter1.deepClone();
        buyter3.getProduct().setName("水果");
        System.out.println(buyter1);
        System.out.println(buyter3);

结果


image.png
上一篇下一篇

猜你喜欢

热点阅读