在ONE模拟器的使用中,我的某个功能需要将整个world都进行深度拷贝,但是world这个类里面包含了大量的自引用类,导致我在深度拷贝的时候踩了大量的坑,目前已经解决,这里进行回顾和总结,以防止遗忘。
1.JAVA深度拷贝方法的选择。查阅了网上关于java深度复制的方法,觉得序列化拷贝和利用JSON工具实现深度拷贝是两个比较好的方法。区别在于,利用序列化拷贝需要保证你拷贝的对象中,所有类(包括需要复制的对象本身)都必须实现 Serializable 这个类;而利用JSON进行拷贝,需要满足所有类都有全参和空构造方法,很巧world这个类以上两点一个都没满足,所有无论采用哪个工作量都不小,为了尽量减少对源代码的改动,我选择了利用序列化拷贝方法。
具体可参考:java中关于深拷贝的几种方式总结_java_脚本之家
关于序列化进行深度拷贝的方法,查到了一个对其进行封装的方法,但是找不到原地址了,这边直接放代码吧
public class CloneUtil {
public CloneUtil(){}
@SuppressWarnings("unchecked")
public static <T extends Serializable> T cloneObject(T obj) {
T cloneObj = null;
// 序列化
ByteArrayOutputStream bout = null;
ObjectOutputStream oos = null;
try {
bout = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bout);
oos.writeObject(obj);
} catch (IOException e) {
e.getStackTrace();
System.out.println(e.toString());
} finally {
close(oos);
close(bout);
}
// 反序列化
ByteArrayInputStream bin = null;
ObjectInputStream ois = null;
try {
bin = new ByteArrayInputStream(bout.toByteArray());
ois = new ObjectInputStream(bin);
cloneObj = (T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
System.out.println(e.toString());
} finally {
close(ois);
close(bin);
}
return cloneObj;
}
private static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2.自引用类的深度拷贝。实际使用中,由于world中大量自引用类的存在,无论是序列化拷贝还是利用JSON拷贝,都会出现序列化过程中的循坏,即A->B->C->A,导致堆栈溢出。为了解决这个问题,我使用了 transient 修饰存在循坏的成员类,并在后续对其信息进行补充完善,整个过程可以理解为在解循坏,耗费了大量的精力。
ps:自引用类真的有点难顶啊