深拷贝和浅拷贝了解吗?什么是引用拷贝

685 阅读4分钟

1、深、浅拷贝定义

  • 浅拷贝: 浅拷贝是指仅仅拷贝对象的引用而不是对象本身,也就是说,原对象和拷贝对象会共享同一个引用,任何一方的变化都会影响到另一方。在Java中,可以使用clone()方法实现浅拷贝。

  • 深拷贝: 深拷贝是指拷贝对象本身,而不是对象引用,也就是说,原对象和拷贝对象互不影响,它们的属性和数据都是独立的。在Java中,可以通过序列化和反序列化、使用ObjectInputStream和ObjectOutputStream实现深拷贝。

2、深、浅拷贝区别

  1. 浅拷贝只是拷贝对象的引用,两个引用指向同一个对象;而深拷贝是创建一个新的对象,拷贝原始对象中的所有字段和属性,并且创建新对象的内存地址和原始对象不同。
  2. 浅拷贝对属性是基本数据类型的对象拷贝符合预期,但是对于属性是引用数据类型的对象拷贝,原始对象和拷贝对象会共享同一个引用,任何一方的变化都会影响到另一方;深拷贝不仅能拷贝基本数据类型的属性,还能递归拷贝引用类型的属性,从而真正实现对象拷贝。
  3. 深拷贝相对于浅拷贝速度较慢并且花销较大。

因此,在Java开发中,需要根据实际需求来选择使用浅拷贝还是深拷贝。如果对象的属性中包含了大量的引用类型数据,那么建议使用深拷贝;如果只是简单的基本数据类型,浅拷贝就足够了。

3、引用拷贝、对象拷贝

引用拷贝就是拷贝引用地址,两个不同的引用指向同一个对象。

引用拷贝分为深拷贝和浅拷贝。对象拷贝分为深拷贝、浅拷贝和引用拷贝。

4、深拷贝怎么实现?

  1. 通过 JSON.parse() 和 JSON.stringify() 方法实现深拷贝。这种方法的原理是将原始对象转换为字符串后再进行解析,这样就可以创建一个新的对象,与原始对象没有任何关联。 示例代码:

    let obj = {a: 1, b: {c: 2}};
    let newObj = JSON.parse(JSON.stringify(obj));
    
  2. 通过递归地遍历原始对象并创建新的对象来实现深拷贝。这种方法的原理是遍历原始对象的每一个属性,如果属性是一个对象,则递归调用深拷贝函数,如果属性是一个基本类型,则直接复制。示例代码:

    function deepClone(obj) {
      let newObj = Array.isArray(obj) ? [] : {};
      for (let key in obj) {
        if (typeof obj[key] === 'object' && obj[key] !== null) {
          newObj[key] = deepClone(obj[key]);
        } else {
          newObj[key] = obj[key];
        }
      }
      return newObj;
    }
    
    let obj = {a: 1, b: {c: 2}};
    let newObj = deepClone(obj);
    

    需要注意的是,使用递归的方式实现深拷贝时,需要处理循环引用的情况,否则会导致栈溢出。可以通过记录已经拷贝过的对象来解决这个问题。

  3. 使用 jQuery 的 extend 方法可以实现深拷贝。该方法可以将多个对象的属性合并到一个新对象中,并且是深拷贝,即会递归地复制对象的所有属性。示例代码:

    let obj1 = {a: 1, b: {c: 2}};
    let obj2 = {d: 3};
    let newObj = $.extend(true, {}, obj1, obj2);
    

    上述代码中,通过传递 true 参数来指示进行深拷贝。通过传递空对象 {} 作为目标对象,可以创建一个新的对象,与原始对象没有任何关联。

    需要注意的是,使用 jQuery 的 extend 方法会增加代码的复杂度和运行时的开销,因此在项目中需要谨慎使用。如果只需要进行浅拷贝,可以使用 ES6 中的 Object.assign() 方法,其语法类似于 jQuery 的 extend 方法,但只进行浅拷贝。

使用序列化和反序列化可以实现深拷贝,具体实现步骤如下:

  1. 将原始对象转换为字符串。

可以使用 JSON.stringify() 方法将原始对象转换为字符串,这样可以将对象的所有属性都转换为字符串,并且可以保留对象中的各种类型。

  1. 将字符串转换为新的对象。

可以使用 JSON.parse() 方法将字符串解析为新的对象,这样可以创建一个新的对象,与原始对象没有任何关联。示例代码:

let obj = {a: 1, b: {c: 2}};
let newObj = JSON.parse(JSON.stringify(obj));

需要注意的是,使用序列化和反序列化实现深拷贝时,需要处理循环引用的情况,否则会导致栈溢出。可以通过记录已经拷贝过的对象来解决这个问题。

同时,使用序列化和反序列化实现深拷贝的方法也有一些限制,例如无法拷贝函数和原型链上的属性等。因此,需要根据具体情况选择合适的方法来实现深拷贝。