// 實體類需實現 Cloneable
public class Tire implements Cloneable {
public String color; public int radius;
@Override protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 淺拷貝
}
}
public class Car implements Cloneable {
public String name, color; public Tire tire;
@Override protected Object clone() throws CloneNotSupportedException {
Car car = (Car) super.clone();
car.tire = (Tire) tire.clone(); // 手動深拷貝引用字段
return car;
}
}
缺點:侵入性強(需實現接口、重寫方法)、引用鏈長時維護地獄、構造器不被調用可能導致不一致。
@SuppressWarnings("unchecked")
public static T deepClone(T obj) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis)) {
oos.writeObject(obj);
return (T) ois.readObject();
} catch (Exception e) { throw new RuntimeException(e); }
}
優點:自動處理完整對象圖、無需手動遞歸。
缺點:需實現 Serializable、性能差(IO 開銷)、transient/static 字段不拷貝、構造器不調用、單例模式破壞。
// 一行代碼,內部基於序列化
public Object deepClone(Object obj) {
return SerializationUtils.clone((Serializable) obj);
}
依賴:org.apache.commons:commons-lang3。同方案二優缺點。
// Jackson ObjectMapper mapper = new ObjectMapper(); Car copy = mapper.readValue(mapper.writeValueAsString(car), Car.class); // Gson Gson gson = new Gson(); Car copy = gson.fromJson(gson.toJson(car), Car.class);
優勢:無需實現接口、性能優於 Java 原生序列化、可控字段(@JsonIgnore)、跨語言兼容、人類可讀調試友好。
private object DeepCopy(object obj) {
if (obj == null) return null;
Type type = obj.GetType();
// 值類型直接返回
if (type.IsValueType) return obj;
// 創建實例(需無參構造器)
object copy = Activator.CreateInstance(type);
// 遍歷字段
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
object fieldValue = field.GetValue(obj);
if (fieldValue == null) continue;
if (fieldValue is ICloneable)
field.SetValue(copy, ((ICloneable)fieldValue).Clone());
else
field.SetValue(copy, DeepCopy(fieldValue)); // 遞歸
}
// 遍歷屬性
foreach (PropertyInfo prop in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
if (!prop.CanRead || !prop.CanWrite) continue;
object propValue = prop.GetValue(obj);
if (propValue == null) continue;
if (propValue is ICloneable)
prop.SetValue(copy, ((ICloneable)propValue).Clone());
else
prop.SetValue(copy, DeepCopy(propValue));
}
return copy;
}
| 維度 | Java | C# |
|---|---|---|
| 反射性能 | 較慢,需緩存 Field/Method 對象 | 較快,Expression Tree 可編譯委託 |
| 私有成員訪問 | setAccessible(true) 受 SecurityManager 限制 | BindingFlags.NonPublic 直接訪問 |
| 值類型語義 | 基本類型非對象,包裝類不可變 | Struct 值類型語義原生支持 |
| 序列化機制 | Serializable 標記接口,二進制格式 | [Serializable] 屬性,BinaryFormatter/JSON.NET |
| 生態工具 | Jackson、Gson、Kryo、FST | JSON.NET、Protobuf.NET、MessagePack |
Car original = new Car("奔馳", "白", new Tire("黑", 100));
Car copy = deepClone(original);
System.out.println("原對象: " + original.hashCode() + " 輪胎: " + original.tire.hashCode());
System.out.println("拷貝對象: " + copy.hashCode() + " 輪胎: " + copy.tire.hashCode());
// 輸出應顯示不同 hashCode,修改 copy 不影響 original