使用Lang3实现深拷贝(SerializationUtils.clone())
先通过几个问题来引出题目:
对象克隆
什么情况下需要对一个对象进行克隆?
1、保护原始对象:有时候我们需要保护一个对象的原始状态,以便在之后的操作中可以对其进行修改而不影响原始对象。通过克隆对象,我们可以创建一个副本来进行操作,而不改变原始对象的状态。
2、避免共享引用:在某些情况下,多个对象可能引用同一个对象,如果对其中一个对象进行修改,会影响其他对象的行为。通过克隆对象,我们可以创建一个独立的副本,使得每个对象都有自己的引用,互不干扰。
3、提高性能:有时候创建一个新对象的代价比克隆一个已有对象要小。在这种情况下,克隆对象可以避免重复的初始化操作,提高程序的性能。
深拷贝和浅拷贝的区别
浅拷贝:
浅拷贝创建一个新对象,该对象与原始对象共享一部分内存,包括对象的引用。这意味着新对象和原始对象引用相同的子对象。
当进行浅拷贝时,只复制对象的顶层结构,而不会递归复制内部嵌套对象。
修改浅拷贝对象的子对象会影响原始对象中相应的子对象,因为它们引用相同的内存地址。
深拷贝:
深拷贝创建一个全新的对象,该对象和原始对象完全独立,包括对象的引用和内部嵌套对象。
深拷贝会递归复制原始对象及其所有嵌套对象,确保每个对象都是全新的。
修改深拷贝对象的子对象不会影响原始对象,因为它们是完全独立的。
深拷贝代码示例
Apache Commons Lang是一个通用的Java工具库,其中包括了对对象进行深拷贝的方法。具体用法可以参考下面的代码示例:
import org.apache.commons.lang3.SerializationUtils;
public class DeepCopyExample {
public static void main(String[] args) {
// 创建一个原始对象
Person original = new Person("John", new Address("Main Street"));
// 使用SerializationUtils深拷贝对象
Person copy = SerializationUtils.clone(original);
// 改变原始对象的属性
original.setName("Mike");
original.getAddress().setStreet("Second Street");
// 输出结果
System.out.println("Original: " + original); // Original: Person{name='Mike', address=Address{street='Second Street'}}
System.out.println("Copy: " + copy); // Copy: Person{name='John', address=Address{street='Main Street'}}
}
}
class Person implements Serializable {
private String name;
private Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", address=" + address +
'}';
}
}
class Address implements Serializable {
private String street;
public Address(String street) {
this.street = street;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address{" +
"street='" + street + '\'' +
'}';
}
}
需要注意的是,使用SerializationUtils.clone()方法克隆对象时,该对象必须实现Serializable接口,否则将抛出SerializationException异常。
此外,Google Gson中的方法也可以实现深拷贝。
// 示例代码
SourceBean source = new SourceBean();
source.setName("John");
source.setAge(30);
Gson gson = new Gson();
// 将source对象转换为JSON字符串
String json = gson.toJson(source);
// 将JSON字符串转换回对象,这将得到一个新的对象
TargetBean target = gson.fromJson(json, TargetBean.class);
System.out.println(target.getName()); // Output: "John"
System.out.println(target.getAge()); // Output: 30
// 修改source对象的属性,不会影响target对象
source.setAge(40);
System.out.println(target.getAge()); // Output: 30 (没有变化)