我们应该使用clone或BeanUtils.copyProperties以及原因

通过它的外观 – BeanUtils.copyProperties似乎创建了一个对象的克隆。 如果是这种情况,那么关于实现Cloneable接口的问题(只有不可变对象是新的,因为可变对象有复制的引用)这是最好的,为什么?

我昨天实现了cloneable,然后意识到我必须为非String / Primative元素提供自己的修改。 然后我被告知我正在使用的BeanUtils.copyProperties 。 这两种实现似乎都提供了类似的function。

谢谢

Josh Bloch提供了一些相当不错的论据(包括你提供的论点)断言Cloneable从根本上是有缺陷的,而是支持复制构造函数。 看到这里 。

我还没有遇到过复制不可变对象的实际用例。 您出于特定原因复制对象,可能是为了将一些可变对象集合到一个事务中进行处理,保证在处理单元完成之前不会改变它们。 如果它们已经是不可变的,那么引用就像副本一样好。

BeanUtils.copyProperties通常是一种不那么具有侵入性的复制方式,无需更改要支持的类,它在合成对象时提供了一些独特的灵活性。

也就是说, copyProperties并不总是一刀切。 您可能在某些时候需要支持包含具有专门构造函数但仍可变的类型的对象。 您的对象可以支持内部方法或构造函数来解决这些exception,或者您可以将特定类型注册到某些外部工具进行复制,但它无法到达某些甚至是clone()地方。 这很好,但仍然有限制。

BeanUtils比标准克隆更灵活,只需将字段值从对象复制到另一个对象。 clone方法从同一个类的bean复制字段,但BeanUtils可以为具有相同属性名称的不同类的2个实例执行此操作。

例如,假设您有一个Bean A,它具有字段String date和一个具有相同字段java.util.Date日期的bean B. 使用BeanUtils,您可以复制字符串值并使用DateFormat将其自动转换为日期。

我用它将SOAP对象转换为不具有相同数据类型的Hibernate对象。

我想你正在寻找一份深刻的副本。 您可以在util类中使用以下方法,并将其用于任何类型的对象。

 public static  T copy(T input) { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(input); oos.flush(); byte[] bytes = baos.toByteArray(); bis = new ByteArrayInputStream(bytes); ois = new ObjectInputStream(bis); Object result = ois.readObject(); return (T) result; } catch (IOException e) { throw new IllegalArgumentException("Object can't be copied", e); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Unable to reconstruct serialized object due to invalid class definition", e); } finally { closeQuietly(oos); closeQuietly(baos); closeQuietly(bis); closeQuietly(ois); } } 

从你的问题我想你需要对象的深层副本 。 如果是这种情况,请不要使用clone方法,因为它已在oracle docs中指定它提供关联对象的浅表副本 。 我对BeanUtils.copyProperties API BeanUtils.copyProperties
下面给出了deep copy的简短演示。 在这里,我正在深层复制一个primitive array 。 您可以使用任何类型的对象尝试此代码。

 import java.io.*; class ArrayDeepCopy { ByteArrayOutputStream baos; ByteArrayInputStream bins; public void saveState(Object obj)throws Exception //saving the stream of bytes of object to `ObjectOutputStream`. { baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); oos.close(); } public int[][] readState()throws Exception //reading the state back to object using `ObjectInputStream` { bins = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream oins = new ObjectInputStream(bins); Object obj = oins.readObject(); oins.close(); return (int[][])obj; } public static void main(String[] args) throws Exception { int arr[][]= { {1,2,3}, {4,5,7} }; ArrayDeepCopy ars = new ArrayDeepCopy(); System.out.println("Saving state..."); ars.saveState(arr); System.out.println("State saved.."); System.out.println("Retrieving state.."); int j[][] = ars.readState(); System.out.println("State retrieved..And the retrieved array is:"); for (int i =0 ; i < j.length ; i++ ) { for (int k = 0 ; k < j[i].length ; k++) { System.out.print(j[i][k]+"\t"); } System.out.print("\n"); } } } 

clone创建对象的浅表副本,clone对象始终与原始对象相同。 所有字段,私有或非私有都被复制。

BeanUtils.copyProperties API 将属性值从属bean复制到目标bean,以用于属性名称相同的所有情况。

对我来说,这两个概念没有什么共同之处。

克隆是由您完成的。 如果您尝试克隆的实例包含另一个实例的引用,您也必须将克隆代码写入该实例。 如果实例包含对其他实例的引用链,该怎么办? 因此,如果您自己进行克隆,您可能会错过一个小细节。

另一方面,BeanUtils.copyProperties可以自行处理所有事情。 它减少了你的努力。