1. 浅拷贝
浅拷贝是一种简单的复制方法,它创建一个新的对象,并复制原始对象的所有非静态字段到新对象。如果字段是值类型,那么会进行逐位复制;如果字段是引用类型,那么复制的是引用而不是实际的对象,这意味着,原始对象和复制的对象将共享同一个引用类型的字段
下面是一个简单的例子:
public class Student implements Cloneable {
int id;
String name;
OtherObject other;
// ... 构造方法、getter和setter ...
@Override
public Student clone() {
try {
return (Student) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
在这个例子中,当你调用clone()
方法时,你得到一个新的Student
对象,它的id
和name
字段与原始对象相同,但other
字段仍然是原始对象的引用,这意味着,如果你更改了复制的对象的other
字段,原始对象的other
字段也会被更改
2. 深拷贝
2.1. 手动实现深拷贝
对于每个引用类型的字段,你需要手动创建新的实例并进行赋值,这种方法需要大量的代码,并且容易出错
2.2. 克隆
你可以在每个引用类型字段上实现Cloneable
接口并重写clone()
方法,这需要为每个引用类型字段编写额外的代码来创建新的实例
2.3. 使用序列化与反序列化
这是实现深拷贝的一种更简单的方法。你可以将对象序列化为字节数组,然后再将字节数组反序列化为新的对象。这种方法的好处是它可以处理复杂的对象图,但需要注意的是,所有的相关对象也必须实现序列化接口
下面是一个简单的例子:
import java.io.*;
public class DeepCopyExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建一个原始对象
OriginalObject original = new OriginalObject("Hello", "World");
System.out.println("原始对象:");
System.out.println(original);
// 深拷贝原始对象
OriginalObject copy = deepCopy(original);
System.out.println("\n复制后的对象:");
System.out.println(copy);
// 修改原始对象的引用字段
original.setOtherObject("Modified");
System.out.println("\n修改原始对象的引用字段:");
System.out.println(original);
// 打印复制后的对象,验证深拷贝的正确性
System.out.println("\n复制后的对象(验证深拷贝):");
System.out.println(copy);
}
/**
* 深拷贝方法,用于创建对象的副本。
* 这里使用序列化与反序列化的方式实现深拷贝。
*/
public static <T extends Serializable> T deepCopy(T obj) throws IOException, ClassNotFoundException {
// 将对象序列化为字节数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(obj);
out.flush();
out.close();
byte[] bytes = bos.toByteArray();
// 从字节数组反序列化对象
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream in = new ObjectInputStream(bais);
@SuppressWarnings("unchecked")
T copy = (T) in.readObject();
in.close();
bais.close();
return copy;
}
}
// 示例对象类,实现Serializable接口以支持序列化与反序列化
class OriginalObject implements Serializable {
private static final long serialVersionUID = 1L;
private String field1;
private OtherObject field2;
public OriginalObject(String field1, String field2) {
this.field1 = field1;
this.field2 = new OtherObject(field2); // 假设OtherObject类也实现了Serializable接口
}
public String getField1() {
return field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public OtherObject getOtherObject() {
return field2;
}
public void setOtherObject(String otherObject) {
this.field2 = new OtherObject(otherObject); // 重新创建OtherObject实例,确保深拷贝的正确性
}
@Override
public String toString() {
return "OriginalObject{" + "field1='" + field1 + '\'' + ", field2=" + field2 + '}';
}
}
// 示例引用类型类,实现Serializable接口以支持序列化与反序列化(这里只是简单示例,实际中可能有更复杂的类结构)
class OtherObject implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public OtherObject(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
2.4. 使用库或框架
有一些库或框架可以帮助你更容易地实现深拷贝,例如:
-
Apache Commons Lang
的SerializationUtils.clone()
方法 -
Google
的Guava
库的ImmutableCopy类
- 工具类
BeanUtils
和PropertyUtils
进行对象复制 -
Hutool
——ObjectUtil
这些工具可以简化深拷贝的实现,并处理许多常见的边界情况