Apache Commons lang:SerializationUtils.clone() 和 BeanUtils.cloneBean() 之间有什么区别,何时使用哪个
Apache Commons lang: What's difference between SerializationUtils.clone() and BeanUtils.cloneBean(), when to use which
在编写测试时,我遇到了克隆对象的要求。通过 apache-commons 找到 2 Utill classes 然后我试图找到我应该使用哪一个,
我试图通过阅读 API 文档来找到差异,但没有找到我应该在
时使用哪个
根据文档:
根据可用的 属性 getter 和 setter 克隆一个 bean,即使 bean class 本身没有实现 Cloneable。
疑问:我应该在 DTO 克隆中使用它吗?
SerializationUtils clone() API doc
根据文档:
使用序列化深度克隆对象。
这比在对象图中的所有对象上手动编写克隆方法要慢很多倍。然而,对于复杂的对象图,或者对于那些不支持深度克隆的对象图,这可能是一个简单的替代实现。当然,所有的对象都必须是可序列化的。
疑问:我应该将它同时用于 DTO 和实体对象吗?或仅适用于实体
SerializationUtils
将始终生成 deep-copy。它将为每个字段创建一个字符串(称为序列化)并将该字符串解析回一个新对象(反序列化)。
这很慢,但你可以保证你的副本是深拷贝。
深拷贝意味着:所有字段都是新对象(而不是对旧对象的引用)。
BeanUtils.cloneBean()
另一方面,将创建对象的浅表副本。下面是一些代码来解释有什么区别:
@Data // lombok annotation, will create getters, setters, equals and hashcode
public class ObjectA implements Serializeable {
private List<String> values = new ArrayList<>();
}
public static main() {
ObjectA objectA = new ObjectA();
objectA().getValues().add("A");
ObjectA beanClone = (ObjectA) BeanUtils.cloneBean(objectA);
ObjectA serialClone = SerializationUtils.clone(objectA);
log.info("Reference-Check: Bean is same: {}", objectA == beanClone); // <- false
log.info("Reference-Check: Bean-Value is same: {}", objectA.getValues() == beanClone.getValues()); // <- true
log.info("Reference-Check: Serial is same: {}", objectA == serialClone); // <- false
log.info("Reference-Check: Serial-Value is same: {}", objectA.getValues() == serialClone.getValues()); // <- false
serialClone.getValues().add("B");
printValues(serialClone.getValues()); // <- prints "['A', 'B']"
printValues(objectA.getValues()); // <- prints "['A']";
beanClone.getValues().add("B");
printValues(beanClone.getValues()); // <- prints "['A', 'B']"
printValues(objectA.getValues()); // <- prints "['A', 'B']"
}
所以对于你的问题:深拷贝“更安全”,你不能修改原始对象的字段。这种对浅拷贝的副作用通常是不需要的。 几乎总是需要深拷贝。
序列化速度很慢,所以最好的方法是复制方法或 copy-constructor.
在编写测试时,我遇到了克隆对象的要求。通过 apache-commons 找到 2 Utill classes 然后我试图找到我应该使用哪一个, 我试图通过阅读 API 文档来找到差异,但没有找到我应该在
时使用哪个根据文档: 根据可用的 属性 getter 和 setter 克隆一个 bean,即使 bean class 本身没有实现 Cloneable。
疑问:我应该在 DTO 克隆中使用它吗?
SerializationUtils clone() API doc
根据文档:
使用序列化深度克隆对象。
这比在对象图中的所有对象上手动编写克隆方法要慢很多倍。然而,对于复杂的对象图,或者对于那些不支持深度克隆的对象图,这可能是一个简单的替代实现。当然,所有的对象都必须是可序列化的。
疑问:我应该将它同时用于 DTO 和实体对象吗?或仅适用于实体
SerializationUtils
将始终生成 deep-copy。它将为每个字段创建一个字符串(称为序列化)并将该字符串解析回一个新对象(反序列化)。
这很慢,但你可以保证你的副本是深拷贝。
深拷贝意味着:所有字段都是新对象(而不是对旧对象的引用)。
BeanUtils.cloneBean()
另一方面,将创建对象的浅表副本。下面是一些代码来解释有什么区别:
@Data // lombok annotation, will create getters, setters, equals and hashcode
public class ObjectA implements Serializeable {
private List<String> values = new ArrayList<>();
}
public static main() {
ObjectA objectA = new ObjectA();
objectA().getValues().add("A");
ObjectA beanClone = (ObjectA) BeanUtils.cloneBean(objectA);
ObjectA serialClone = SerializationUtils.clone(objectA);
log.info("Reference-Check: Bean is same: {}", objectA == beanClone); // <- false
log.info("Reference-Check: Bean-Value is same: {}", objectA.getValues() == beanClone.getValues()); // <- true
log.info("Reference-Check: Serial is same: {}", objectA == serialClone); // <- false
log.info("Reference-Check: Serial-Value is same: {}", objectA.getValues() == serialClone.getValues()); // <- false
serialClone.getValues().add("B");
printValues(serialClone.getValues()); // <- prints "['A', 'B']"
printValues(objectA.getValues()); // <- prints "['A']";
beanClone.getValues().add("B");
printValues(beanClone.getValues()); // <- prints "['A', 'B']"
printValues(objectA.getValues()); // <- prints "['A', 'B']"
}
所以对于你的问题:深拷贝“更安全”,你不能修改原始对象的字段。这种对浅拷贝的副作用通常是不需要的。 几乎总是需要深拷贝。
序列化速度很慢,所以最好的方法是复制方法或 copy-constructor.