目录
深拷贝和浅拷贝是对象复制的两种方式,它们在处理引用类型的字段时存在显著差异。下面将详细介绍它们的含义、区别,并提供代码示例。
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
ModelMapper
和 MapStruct
都可以用来轻松地进行对象之间的映射,借此实现深拷贝。
7.Hutool 工具类
Hutool 提供了简单易用的工具类,可以进行深拷贝和浅拷贝:
浅拷贝
Person copy = ShallowUtil.clone(original);
深拷贝
Person deepCopy = CloneUtil.clone(original);
8.Guava 中的相关工具类
Guava 提供了 Immutable
集合来避免可变性,虽然不是直接的拷贝方法,但可以帮助管理不可变对象。
-
ImmutableList
、
ImmutableSet和
ImmutableMap 用于创建不可变的集合,这样可以避免浅拷贝的问题。 -
不可变集合在创建后无法更改,这使得它们特别适合于多线程环境和函数式编程风格。
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
}
}
总结
-
浅拷贝和深拷贝分别适用于不同的场景。
-
根据需要选择合适的拷贝方法,并利用现有的框架和库简化工作。