目 录CONTENT

文章目录

深拷贝和浅拷贝

半糖
2024-08-18 / 0 评论 / 0 点赞 / 10 阅读 / 15440 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2024-08-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

深拷贝

概念

深拷贝是一种创建新对象的方法,它不仅复制对象本身,还会递归地复制对象内部的所有引用类型。这意味着对于对象中的每个引用类型成员,都会创建一个新的实例,并且将原对象中的数据复制到新对象中。这样可以确保新对象与原对象完全独立,修改其中一个对象的内容不会影响另一个对象。

特点

  • 对于基本类型的数据成员,会复制其值。

  • 对于引用类型的数据成员,会递归地复制整个对象。

实现方式

手动实现

  1. 遍历对象的所有字段,对于引用类型字段,递归地进行深拷贝。

  2. 对于基本类型字段,直接复制值。

代码示例

被拷贝的对象:Person、Address,Person中聚合Address用于测试深拷贝

package com.ysj.correlation.deepShallowCopy.deep.manual;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 人
 */
@Data
@AllArgsConstructor
@ToString
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 地址
     */
    private Address address;

}
package com.ysj.correlation.deepShallowCopy.deep.manual;

import lombok.*;

/**
 * 地址
 */
@Data
@AllArgsConstructor
@ToString
public class Address {

    /**
     * 城市
     */
    private String city;

    /**
     * 街道
     */
    private String street;

}

客户端:DeepCopyClient,deepCopy()手动实现深拷贝

package com.ysj.correlation.deepShallowCopy.deep.manual;

public class DeepCopyClient {

    /**
     * 手动实现深拷贝
     * @param original
     * @return
     */
    public static Person deepCopy(Person original) {
        if (original == null) {
            return null;
        }
        Address addressCopy = new Address(original.getAddress().getStreet(), original.getAddress().getCity());
        return new Person(original.getName(), original.getAge(), addressCopy);
    }

    public static void main(String[] args) {
        Address address = new Address("重庆","长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = deepCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

序列化和反序列化实现

  1. 将对象序列化为字节流或某种文本格式(如 JSON)。

  2. 再从序列化的数据中反序列化出一个新对象。

代码示例

被拷贝的对象:Person、Address,Person中聚合Address用于测试深拷贝,都实现Serializable

package com.ysj.correlation.deepShallowCopy.deep.serialization;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

/**
 * 人
 */
@Data
@AllArgsConstructor
@ToString
public class Person implements Serializable {
    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 地址
     */
    private Address address;

}
package com.ysj.correlation.deepShallowCopy.deep.serialization;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

/**
 * 地址
 */
@Data
@AllArgsConstructor
@ToString
public class Address implements Serializable {

    /**
     * 城市
     */
    private String city;

    /**
     * 街道
     */
    private String street;


}

客户端:DeepCopyClient,deepCopy()序列化和反序列化实现深拷贝

package com.ysj.correlation.deepShallowCopy.deep.serialization;

import java.io.*;

public class DeepCopyClient {

    /**
     * 序列化和反序列化实现深拷贝
     * @param original
     * @return
     * @param <T>
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static <T> T deepCopy(T original) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(original);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        return (T) in.readObject();
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Address address = new Address("重庆","长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = deepCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

第三方库实现

  1. org.apache.commons.lang3.SerializationUtils.clone() 实现深拷贝,推荐使用(被拷贝对象必须实现Serializable)

  2. com.fasterxml.jackson.databind.ObjectMapper的 writeValueAsString() 和 readValue() 实现深拷贝,但是不推荐。(与序列化和反序列化实现类似,只不过使用json字符串实现序列化和反序列化)

  3. cn.hutool.core.util.ObjectUtil.clone() 实现深拷贝

    1. 被拷贝对象实现Serializable接口(如果没实现返回null),直接就是深拷贝,推荐使用

    2. 被拷贝对象实现Cloneable接口,调用自己的clone()实现深拷贝

代码示例(以hutool工具为例)

客户端:DeepCopyClient,deepCopy()调用ObjectUtil.clone()实现深拷贝,Person和Address使用实现了Serializable的

package com.ysj.correlation.deepShallowCopy.deep.party3;

import cn.hutool.core.util.ObjectUtil;
import com.ysj.correlation.deepShallowCopy.deep.serialization.Address;
import com.ysj.correlation.deepShallowCopy.deep.serialization.Person;

import java.io.*;

public class DeepCopyClient {

    /**
     * ObjectUtil.clone()实现深拷贝
     *
     * @param original
     * @param <T>
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static <T> T deepCopy(T original) {
        return ObjectUtil.clone(original);
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Address address = new Address("重庆", "长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = deepCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

浅拷贝

概念

浅拷贝是指创建一个新对象,这个新对象具有原始对象属性值的一份精确拷贝。如果属性是基本类型(如整数、浮点数、字符串等),拷贝的就是基本类型的值;如果属性是引用类型(如对象或者数组),拷贝的就是内存地址,即新旧对象共享同一块内存区域。

特点

  • 对于基本数据类型的字段,会复制其值。

  • 对于引用数据类型的字段,只会复制其引用(内存地址)。

实现方式

手动实现

被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝

package com.ysj.correlation.deepShallowCopy.deep.manual;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 人
 */
@Data
@AllArgsConstructor
@ToString
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 地址
     */
    private Address address;

}
package com.ysj.correlation.deepShallowCopy.deep.manual;

import lombok.*;

/**
 * 地址
 */
@Data
@AllArgsConstructor
@ToString
public class Address {

    /**
     * 城市
     */
    private String city;

    /**
     * 街道
     */
    private String street;

}

客户端:DeepCopyClient,deepCopy()手动实现浅拷贝

package com.ysj.correlation.deepShallowCopy.shallow.manual;

public class ShallowCopyClient {

    /**
     * 手动实现浅拷贝
     * @param original
     * @return
     */
    public static Person shallowCopy(Person original) {
        if (original == null) {
            return null;
        }
        return new Person(original.getName(), original.getAge(), original.getAddress());
    }

    public static void main(String[] args) {
        Address address = new Address("重庆","长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = shallowCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

浅拷贝构造器实现

  1. 如果类提供了适当的构造器,可以直接使用这些构造器来创建新对象。

  2. 对于引用类型成员,直接使用原对象的引用。

代码示例

被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝,浅拷贝构造器进行浅拷贝

package com.ysj.correlation.deepShallowCopy.shallow.constructor;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 人
 */
@Data
@AllArgsConstructor
@ToString
public class Person {

    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 地址
     */
    private Address address;

    /**
     * 浅拷贝构造器
     * @param original
     */
    public Person(Person original) {
        this.name = original.name;
        this.age = original.age;
        this.address = original.address; // 只复制引用
    }

}
package com.ysj.correlation.deepShallowCopy.shallow.constructor;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 地址
 */
@Data
@AllArgsConstructor
@ToString
public class Address {

    /**
     * 城市
     */
    private String city;

    /**
     * 街道
     */
    private String street;

}

客户端:DeepCopyClient,使用浅拷贝构造器浅拷贝

package com.ysj.correlation.deepShallowCopy.shallow.constructor;

public class ShallowCopyClient {

    public static void main(String[] args) {
        Address address = new Address("重庆","长生桥");
        Person person = new Person("小帅", 30, address);

        // 使用浅拷贝构造器浅拷贝
        Person personCopy = new Person(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }

}

clone()方法实现

代码示例

被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝,都实现Cloneable,并重写clone()方法

package com.ysj.correlation.deepShallowCopy.shallow.cloneable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 人
 */
@Data
@AllArgsConstructor
@ToString
public class Person implements Cloneable {
    /**
     * 姓名
     */
    private String name;

    /**
     * 年龄
     */
    private int age;

    /**
     * 地址
     */
    private Address address;

    public Person clone() {
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

}
package com.ysj.correlation.deepShallowCopy.shallow.cloneable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

/**
 * 地址
 */
@Data
@AllArgsConstructor
@ToString
public class Address implements Cloneable{

    /**
     * 城市
     */
    private String city;

    /**
     * 街道
     */
    private String street;

    public Address clone() {
        try {
            return (Address) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new RuntimeException(e);
        }
    }

}

客户端:DeepCopyClient,shallowCopy调用clone()实现浅拷贝

package com.ysj.correlation.deepShallowCopy.shallow.cloneable;

public class ShallowCopyClient {

    /**
     *  clone()方法实现浅拷贝
     * @param original
     * @return
     */
    public static Person shallowCopy(Person original) {
        if (original == null) {
            return null;
        }
        return original.clone();
    }

    public static void main(String[] args) {
        Address address = new Address("重庆","长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = shallowCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

第三方库实现

  1. cn.hutool.core.bean.BeanUtil.copyProperties() 实现浅拷贝,推荐使用

代码实现

package com.ysj.correlation.deepShallowCopy.shallow.party3;

import cn.hutool.core.bean.BeanUtil;
import com.ysj.correlation.deepShallowCopy.shallow.manual.Address;
import com.ysj.correlation.deepShallowCopy.shallow.manual.Person;

public class ShallowCopyClient {

    /**
     * BeanUtil.copyProperties()实现浅拷贝
     *
     * @param original
     * @return
     */
    public static Person shallowCopy(Person original) {
        if (original == null) {
            return null;
        }
        return BeanUtil.copyProperties(original, Person.class);
    }

    public static void main(String[] args) {
        Address address = new Address("重庆", "长生桥");
        Person person = new Person("小帅", 30, address);

        Person personCopy = shallowCopy(person);
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);

        person.getAddress().setStreet("同景");

        System.out.println("修改后:");
        System.out.println("原始: " + person);
        System.out.println("复制: " + personCopy);
    }
}

0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区