首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

C# vs Java 深拷貝實現對比:反射、序列化、第三方庫與最佳實踐

     編輯:Java 綜合教學

Java 深拷貝四大方案對比

方案一:Cloneable 接口 + 重寫 clone()

// 實體類需實現 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;
    }
}

缺點:侵入性強(需實現接口、重寫方法)、引用鏈長時維護地獄、構造器不被調用可能導致不一致。

方案二:序列化/反序列化 (Serializable)

@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 字段不拷貝、構造器不調用、單例模式破壞。

方案三:Apache Commons Lang

// 一行代碼,內部基於序列化
public Object deepClone(Object obj) {
    return SerializationUtils.clone((Serializable) obj);
}

依賴:org.apache.commons:commons-lang3。同方案二優缺點。

方案四:JSON 序列化 (Jackson/Gson) - 推薦現代項目

// 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)、跨語言兼容、人類可讀調試友好。

C# 純反射深拷貝實現(無需接口)

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;
}

核心差異總結

維度JavaC#
反射性能較慢,需緩存 Field/Method 對象較快,Expression Tree 可編譯委託
私有成員訪問setAccessible(true) 受 SecurityManager 限制BindingFlags.NonPublic 直接訪問
值類型語義基本類型非對象,包裝類不可變Struct 值類型語義原生支持
序列化機制Serializable 標記接口,二進制格式[Serializable] 屬性,BinaryFormatter/JSON.NET
生態工具Jackson、Gson、Kryo、FSTJSON.NET、Protobuf.NET、MessagePack

生產環境選型建議

  1. 首選 JSON 序列化(Jackson/Gson):無侵入、性能好、調試易、跨語言
  2. 高性能場景:Kryo、FST、Protobuf(二進制、Schema 驅動)
  3. 領域模型嚴格:手動拷貝構造器/Builder 模式,保證業務不變量
  4. 避免:原生序列化、Cloneable(維護成本高、陷阱多)

深拷貝測試驗證

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
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved