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


当前回答

下面是一种通用的深度克隆方法,使用字节数组流进行对象序列化和反序列化(以避免写入文件)。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepClone(T t) {
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);) {
        oos.writeObject(t);
        byte[] bytes = baos.toByteArray();
        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
            return (T) ois.readObject();
        }
    } catch (IOException | ClassNotFoundException e) {
        throw new RuntimeException(e);
    }
}

其他回答

这是一个关于如何深度克隆任何对象的简单示例: 首先实现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();

才能得到克隆体。

一个安全的方法是序列化对象,然后反序列化。这确保了所有内容都是全新的参考。

这里有一篇关于如何有效地做到这一点的文章。

注意:类可以重写序列化,这样就不会创建新的实例,例如单例。当然,如果你的类不是序列化的,这也行不通。

BeanUtils在深度克隆bean方面做得非常好。

BeanUtils.cloneBean(obj);

您可以使用具有简单API的库,并使用反射执行相对快速的克隆(应该比序列化方法快)。

Cloner cloner = new Cloner();

MyClass clone = cloner.deepClone(o);
// clone is a deep-clone of o

对于复杂的对象,当性能不重要时,我使用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);
}