实现深度对象复制函数有点困难。您采取什么步骤来确保原始对象和克隆对象没有共享引用?


当前回答

对于复杂的对象,当性能不重要时,我使用json库,如gson 要将对象序列化为json文本,然后反序列化文本以获得新对象。

gson,基于反射将工作在大多数情况下,除了瞬态字段将不会被复制和对象的循环引用与原因StackOverflowError。

public static <T> T copy(T anObject, Class<T> classInfo) {
    Gson gson = new GsonBuilder().create();
    String text = gson.toJson(anObject);
    T newObject = gson.fromJson(text, classInfo);
    return newObject;
}
public static void main(String[] args) {
    String originalObject = "hello";
    String copiedObject = copy(originalObject, String.class);
}

其他回答

你可以在Apache Commons Lang中使用org.apache.commons.lang3.SerializationUtils.clone(T)来做一个基于序列化的深度克隆,但是要小心——性能非常糟糕。

一般来说,最好的做法是为需要克隆的对象图中对象的每个类编写自己的克隆方法。

您可以使用序列化进行深度复制,而无需创建文件。

您希望深度复制的对象需要实现可序列化。如果类不是final或不能修改,则扩展类并实现serializable。

将你的类转换为字节流:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
oos.close();
bos.close();
byte[] byteData = bos.toByteArray();

从字节流中恢复类:

ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
Object object = new ObjectInputStream(bais).readObject();

深度复制只能在每个班级同意的情况下进行。如果您可以控制类层次结构,那么您可以实现可克隆接口并实现Clone方法。否则进行深度复制是不可能安全的,因为对象也可能共享非数据资源(例如数据库连接)。一般来说,深度复制在Java环境中被认为是不好的做法,应该通过适当的设计实践来避免。

这是一个关于如何深度克隆任何对象的简单示例: 首先实现serializable

public class CSVTable implements Serializable{
    Table<Integer, Integer, String> table; 
    public CSVTable() {
        this.table = HashBasedTable.create();
    }
    
    public CSVTable deepClone() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);

            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            return (CSVTable) ois.readObject();
        } catch (IOException e) {
            return null;
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

}

然后

CSVTable table = new CSVTable();
CSVTable tempTable = table.deepClone();

才能得到克隆体。

一个非常快速和简单的一行程序解决方案是使用Jackson。

看一下示例代码片段:

ObjectMapper objectMapper = new ObjectMapper();

MyClass deepCopyObject = objectMapper
  .readValue(objectMapper.writeValueAsString(originalObject), MyClass.class);

在上面的例子中:“MyClass”指的是你想要复制的对象的类。

解释:我们只是试图将原始对象序列化为字符串,然后将字符串反序列化回对象,从而获得一个深度副本。 了解更多关于ObjectMapper的信息,请访问:https://fasterxml.github.io/jackson-databind/javadoc/2.7/com/fasterxml/jackson/databind/ObjectMapper.html