美文网首页
Java的深拷贝与浅拷贝

Java的深拷贝与浅拷贝

作者: Responsibility_ | 来源:发表于2020-04-28 09:04 被阅读0次

在学习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

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

浅拷贝
  • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
    举个例子:
    我们创建一个商品类,包含属性,构造方法与get set 方法
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

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


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

  • 方式1重写clone方法,对下一层对象进行clone
    Product类中实现父类的clone方法
@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:对象序列化,类都要实现Serializable接口,如果又不需要序列化的属性使用transient关键字
    //方法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

相关文章

  • java 对象的拷贝

    拷贝:即复制 对象拷贝:即对象复制 java 对象拷贝分类:浅拷贝、深拷贝 java 对象的浅拷贝和深拷贝针对包含...

  • Java基础 - 深拷贝和浅拷贝

    Java 的深拷贝和浅拷贝 什么是深拷贝、浅拷贝 (深克隆、浅克隆)? 在 Java 中,数据类型分为 基本数据类...

  • Java------List的深拷贝与浅拷贝

    Java的浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。 浅拷贝(Shallow Copy) ...

  • java中的深拷贝和浅拷贝

    简单记录一下java中的深拷贝和浅拷贝,深拷贝和浅拷贝只是针对对象而言的. 1 深拷贝代码 2 浅拷贝代码 3 测...

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • Java的浅拷贝与深拷贝

    Java的浅拷贝与深拷贝 一、概念 浅拷贝浅拷贝仅仅复制所考虑的对象(包括对象中的基本变量),而不复制它所引用的对...

  • 认识js下的浅拷贝与深拷贝

    浅拷贝与深拷贝 首先深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一...

  • 深拷贝和浅拷贝

    干货!深拷贝和浅拷贝的区别 深拷贝才是拷贝,浅拷贝就是Retain Copy与Retain的区别 Copy: 根据...

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • Objective-C中的浅拷贝和深拷贝

    Objective-C中的浅拷贝和深拷贝IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解iOS ...

网友评论

      本文标题:Java的深拷贝与浅拷贝

      本文链接:https://www.haomeiwen.com/subject/desmwhtx.html