Java实例 深层复制、浅层复制和懒惰复制

Java实例 深层复制、浅层复制和懒惰复制

在面向对象编程中,对象复制是创建一个现有对象的副本,产生的对象被称为对象副本或简单的原始对象的副本。有几种方法来复制一个对象,最常见的是通过复制构造器或克隆。

我们可以将克隆定义为 “创建一个对象的副本 “。浅层、深层和懒惰复制与克隆过程有关。

这实际上是创建副本对象的三种方法。

浅层复制

  • 每当我们使用克隆方法的默认实现时,我们会得到对象的浅层拷贝,这意味着它创建了新的实例,并将对象的所有字段复制到新的实例中,并将其作为对象类型返回,我们需要明确地将其铸回我们的原始对象。这就是对象的浅层拷贝。
  • 对象类的clone()方法支持对象的浅层拷贝。如果对象在浅层拷贝中包含基元和非基元或引用类型的变量,那么克隆的对象也会指向原始对象所指向的同一个对象,因为只有对象的引用被复制,而不是所指的对象本身。
  • 这就是为什么在Java中被称为浅层复制或浅层克隆。如果只有原始类型的字段或Immutable对象,那么Java中的浅拷贝和深拷贝就没有区别。
//code illustrating shallow copy
public class Ex {
  
    private int[] data;
  
    // makes a shallow copy of values
    public Ex(int[] values) {
        data = values;
    }
  
    public void showData() {
        System.out.println( Arrays.toString(data) );
    }
}

上面的代码显示了浅层复制。data仅仅是指与vals相同的数组。

深层复制、浅层复制和懒惰复制的Java实例

如果值的元素通过其他引用被改变,这可能导致不愉快的副作用。

public class UsesEx{
  
    public static void main(String[] args) {
        int[] vals = {3, 7, 9};
        Ex e = new Ex(vals);
        e.showData(); // prints out [3, 7, 9]
        vals[0] = 13;
        e.showData(); // prints out [13, 7, 9]
  
        // Very confusing, because we didn't
        // intentionally change anything about 
        // the object e refers to.
    }
}
Output 1 : [3, 7, 9]
Output 2 : [13, 7, 9]

深度拷贝

  • 每当我们需要自己的拷贝而不使用默认的实现时,我们称之为深度拷贝,每当我们需要对对象进行深度拷贝时,我们需要根据我们的需要来实现。
  • 所以对于深度拷贝,我们需要确保所有的成员类也实现了Cloneable接口,并且覆盖了对象类的clone()方法。

深度复制意味着实际上是创建一个新的数组并复制其值。

// Code explaining deep copy
public class Ex {
      
    private int[] data;
  
    // altered to make a deep copy of values
    public Ex(int[] values) {
        data = new int[values.length];
        for (int i = 0; i < data.length; i++) {
            data[i] = values[i];
        }
    }
  
    public void showData() {
        System.out.println(Arrays.toString(data));
    }
}

深层复制、浅层复制和懒惰复制的Java实例

public class UsesEx{
  
    public static void main(String[] args) {
        int[] vals = {3, 7, 9};
        Ex e = new Ex(vals);
        e.showData(); // prints out [3, 7, 9]
        vals[0] = 13;
        e.showData(); // prints out [3, 7, 9]
  
       // changes in array values will not be 
       // shown in data values. 
    }
}
Output 1 : [3, 7, 9]
Output 2 : [3, 7, 9]

对数组vals的改变不会导致数组数据的改变。

何时使用什么

对于浅拷贝和深拷贝的选择没有定义硬性规则,但是通常我们应该记住,如果一个对象只有原始字段,那么显然我们应该选择浅拷贝,但是如果对象有对其他对象的引用,那么根据需求,应该进行浅拷贝或深拷贝。如果引用没有更新,那么就没有必要启动深度拷贝。
懒惰 拷贝

懒惰拷贝可以定义为浅层拷贝和深层拷贝的结合。该机制遵循一个简单的方法–在初始状态下,使用浅拷贝方法。一个计数器也被用来跟踪有多少对象共享数据。当程序想要修改原始对象时,它会检查该对象是否被共享。如果对象是共享的,则启动深度拷贝机制。
小结

在浅度拷贝中,只有原始数据类型的字段被拷贝,而对象的引用没有被拷贝。深度复制涉及原始数据类型和对象引用的复制。对于何时进行浅层复制和何时进行深层复制,没有硬性规定。懒惰复制是这两种方法的组合

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程