实现深度对象复制函数有点困难。您采取什么步骤来确保原始对象和克隆对象没有共享引用?
当前回答
一个安全的方法是序列化对象,然后反序列化。这确保了所有内容都是全新的参考。
这里有一篇关于如何有效地做到这一点的文章。
注意:类可以重写序列化,这样就不会创建新的实例,例如单例。当然,如果你的类不是序列化的,这也行不通。
其他回答
使用Jackson序列化和反序列化对象。此实现不需要对象实现Serializable类。
<T> T clone(T object, Class<T> clazzType) throws IOException {
final ObjectMapper objMapper = new ObjectMapper();
String jsonStr= objMapper.writeValueAsString(object);
return objMapper.readValue(jsonStr, clazzType);
}
XStream在这种情况下非常有用。这是一个简单的代码来做克隆
private static final XStream XSTREAM = new XStream();
...
Object newObject = XSTREAM.fromXML(XSTREAM.toXML(obj));
一些人提到了使用或重写Object.clone()。不要这样做。Object.clone()存在一些主要问题,在大多数情况下不鼓励使用它。请参见Joshua Bloch的“Effective Java”中的第11项,以获得完整的答案。我相信您可以安全地在基本类型数组上使用Object.clone(),但除此之外,您还需要明智地正确使用和重写clone。
依赖于序列化(XML或其他方式)的方案是拙劣的。
这个问题没有简单的答案。如果你想要深度复制一个对象,你必须遍历对象图,并通过对象的复制构造函数或静态工厂方法显式复制每个子对象,然后再深度复制子对象。不需要复制不可变对象(例如字符串)。顺便说一句,出于这个原因,您应该支持不可变性。
您可以使用序列化进行深度复制,而无需创建文件。
您希望深度复制的对象需要实现可序列化。如果类不是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();
下面是一种通用的深度克隆方法,使用字节数组流进行对象序列化和反序列化(以避免写入文件)。
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);
}
}
推荐文章
- List、List<?>, List<T>, List<E>, List<Object>
- 在Java中转换字符串到日历对象
- 在java中使用wait()和notify()的简单场景
- 增强的for循环中的Null检查
- 类中的Python装饰器
- c# vs Java Enum(适合c#新手)
- 如何在不强制转换的情况下将double转换为long ?
- for循环和for-each循环在性能上有区别吗?
- 你如何比较两个版本的字符串在Java?
- 为什么在Java和。net中不能修改字符串?
- java.util.Random真的那么随机吗?我怎么能生成52!(阶乘)可能的序列?
- ZoneOffset之间的区别是什么。UTC和ZoneId.of(“UTC”)?
- 类未找到:IntelliJ中的空测试套件
- 将JAR文件添加到Spark作业- Spark -submit
- REST API - dto还是不是?