深拷贝|浅拷贝

目录

1. 深拷贝(Deep Copy)

2. 浅拷贝(Shallow Copy)

3. 深拷贝和浅拷贝的区别

4. 示例代码

浅拷贝示例

深拷贝示例

5.常用的方法

1.Java Object.clone() 方法

2.序列化与反序列化

6.Spring Boot 中的常用方法

使用 SerializationUtils

使用 ModelMapper 或 MapStruct

7.Hutool 工具类

浅拷贝

深拷贝

8.Guava 中的相关工具类

总结


深拷贝和浅拷贝是对象复制的两种方式,它们在处理引用类型的字段时存在显著差异。下面将详细介绍它们的含义、区别,并提供代码示例。

1. 深拷贝(Deep Copy)

  • 定义:深拷贝创建一个新对象,并且复制原对象中的所有字段,包括引用类型的字段。对于每个引用类型的字段,它都会创建一个新的实例,确保源对象和目标对象之间没有任何共享的引用。

    • 递归地复制所有子对象。即使原始对象或拷贝对象修改其子对象,也不会互相影响。

  • 特点

    • 基本数据类型的值会被复制。

    • 引用数据类型的对象会被完全独立地复制。

2. 浅拷贝(Shallow Copy)

  • 定义:浅拷贝创建一个新对象,该对象与原对象具有相同的值,但对引用类型字段只会复制引用地址,而不复制实际的对象。这意味着原对象和新对象的引用类型属性指向同一块内存。

    • 不递归地复制对象所引用的子对象。它仅复制对象的基本数据类型和对引用类型的引用,因此原始对象和拷贝对象中对引用类型的修改会相互影响。

  • 特点

    • 基本数据类型的值会被复制。

    • 引用数据类型的对象会共享同一个实例。

3. 深拷贝和浅拷贝的区别

特性浅拷贝深拷贝
对基本类型复制其值复制其值
对引用类型复制引用(共同使用同一对象)复制对象(各自独立的对象)
影响修改一个对象的引用类型字段会影响另一个对象修改一个对象不会影响另一个对象

4. 示例代码

浅拷贝示例
class Address {
    String city;
​
    public Address(String city) {
        this.city = city;
    }
}
​
class Person implements Cloneable {
    String name;
    Address address;
​
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
​
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone(); // 浅拷贝
    }
}
​
public class ShallowCopyExample {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);
        Person person2 = (Person) person1.clone(); // 浅拷贝
​
        System.out.println("Before modification:");
        System.out.println("Person1 Address: " + person1.address.city); // 输出: New York
        System.out.println("Person2 Address: " + person2.address.city); // 输出: New York
​
        // 修改 person2 的地址
        person2.address.city = "Los Angeles";
​
        System.out.println("After modification:");
        System.out.println("Person1 Address: " + person1.address.city); // 输出: Los Angeles (共享同一引用)
        System.out.println("Person2 Address: " + person2.address.city); // 输出: Los Angeles
    }
}
深拷贝示例
class Address {
    String city;
​
    public Address(String city) {
        this.city = city;
    }
​
    // 深拷贝方法
    public Address deepCopy() {
        return new Address(this.city);
    }
}
​
class Person {
    String name;
    Address address;
​
    public Person(String name, Address address) {
        this.name = name;
        this.address = address;
    }
​
    // 深拷贝方法
    public Person deepCopy() {
        return new Person(this.name, this.address.deepCopy());
    }
}
​
public class DeepCopyExample {
    public static void main(String[] args) {
        Address address = new Address("New York");
        Person person1 = new Person("Alice", address);
        Person person2 = person1.deepCopy(); // 深拷贝
​
        System.out.println("Before modification:");
        System.out.println("Person1 Address: " + person1.address.city); // 输出: New York
        System.out.println("Person2 Address: " + person2.address.city); // 输出: New York
​
        // 修改 person2 的地址
        person2.address.city = "Los Angeles";
​
        System.out.println("After modification:");
        System.out.println("Person1 Address: " + person1.address.city); // 输出: New York (不受影响)
        System.out.println("Person2 Address: " + person2.address.city); // 输出: Los Angeles
    }
}

5.常用的方法

1.Java Object.clone() 方法
  • Object 类提供的 clone() 方法可以用于实现浅拷贝。

  • 需要实现 Cloneable 接口,并重写 clone() 方法。

2.序列化与反序列化
  • 对象可以通过序列化为字节流,再反序列化为新对象。这种方式可以实现深拷贝。

  • 需要实现 Serializable 接口。

6.Spring Boot 中的常用方法

在 Spring Boot 中,通常使用以下方式来实现深拷贝:

使用 SerializationUtils
import org.springframework.util.SerializationUtils;
​
byte[] bytes = SerializationUtils.serialize(originalObject);
MyObject copiedObject = (MyObject) SerializationUtils.deserialize(bytes);
使用 ModelMapper 或 MapStruct

ModelMapperMapStruct 都可以用来轻松地进行对象之间的映射,借此实现深拷贝。

7.Hutool 工具类

Hutool 提供了简单易用的工具类,可以进行深拷贝和浅拷贝:

浅拷贝
Person copy = ShallowUtil.clone(original);
深拷贝
Person deepCopy = CloneUtil.clone(original);

8.Guava 中的相关工具类

Guava 提供了 Immutable 集合来避免可变性,虽然不是直接的拷贝方法,但可以帮助管理不可变对象。

  • ImmutableListImmutableSetImmutableMap 用于创建不可变的集合,这样可以避免浅拷贝的问题。

  • 不可变集合在创建后无法更改,这使得它们特别适合于多线程环境和函数式编程风格。

import com.google.common.collect.ImmutableList;
​
public class ImmutableListExample {
    public static void main(String[] args) {
        // 创建一个不可变列表
        ImmutableList<String> immutableList = ImmutableList.of("Apple", "Banana", "Cherry");
​
        System.out.println(immutableList);
​
        // 下面的操作会抛出 UnsupportedOperationException,因为该列表是不可变的
        // immutableList.add("Date"); // Uncommenting this line will throw an exception
    }
}
import com.google.common.collect.ImmutableSet;
​
public class ImmutableSetExample {
    public static void main(String[] args) {
        // 创建一个不可变集合
        ImmutableSet<String> immutableSet = ImmutableSet.of("Red", "Green", "Blue");
​
        System.out.println(immutableSet);
​
        // 下面的操作会抛出 UnsupportedOperationException,因为该集合是不可变的
        // immutableSet.add("Yellow"); // Uncommenting this line will throw an exception
    }
}
​
​
import com.google.common.collect.ImmutableMap;
​
public class ImmutableMapExample {
    public static void main(String[] args) {
        // 创建一个不可变映射
        ImmutableMap<String, Integer> immutableMap = ImmutableMap.of(
            "Alice", 30,
            "Bob", 25,
            "Charlie", 35
        );
​
        System.out.println(immutableMap);
​
        // 下面的操作会抛出 UnsupportedOperationException,因为该映射是不可变的
        // immutableMap.put("Dave", 40); // Uncommenting this line will throw an exception
    }
}
​

总结

  • 浅拷贝深拷贝分别适用于不同的场景。

  • 根据需要选择合适的拷贝方法,并利用现有的框架和库简化工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伏颜.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值