2013-03-21 284 views
21

通过它的外观 - BeanUtils.copyProperties似乎创建了一个对象的克隆。如果是这种情况,以及关于实现Cloneable接口的问题(只有不可变对象是新的,其中可变对象具有复制的引用),哪一个最好?为什么?我们应该使用clone还是BeanUtils.copyProperties以及为什么

我昨天实现了可复制,然后意识到我必须提供我自己的修改非字符串/ Primative元素。然后我被告知我正在使用的BeanUtils.copyProperties。这两个实现似乎都提供了类似的功能。

感谢

+0

那你到底在问什么? – 2013-03-21 08:29:16

+1

我们应该使用clone还是BeanUtils.copyProperties,为什么 – Biscuit128 2013-03-21 08:32:09

回答

19

乔希布洛赫提供了一些相当不错的论点(包括你提供的),断言Cloneable是根本上有缺陷,而不是有利于复制构造函数。见here

我还没有遇到复制一个不可变对象的实际用例。由于特定的原因,您正在复制对象,可能是为了将一些可变对象集合分成单个事务进行处理,以确保在处理单元完成之前没有任何东西可以改变它们。如果它们已经是不可变的,那么参考文献与副本一样好。

BeanUtils.copyProperties通常是一种不需要改变要被支持的类的复制方式,它在复制对象时提供了一些独特的灵活性。

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

+0

作为Josh Bloch的有效Java注释的好答案。我可以总结一下,“两者都可以使用取决于senarios”吗?但都有限制。 – 2013-03-24 13:19:27

0

克隆创建对象的浅拷贝,克隆对象始终是同一类的原始之一。所有字段,私人或不是被复制。

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

至于我,这两个概念有一点共同之处。

+3

嗨。我并不质疑你的判断只是扮演魔鬼的主张。克隆的目的是用相同的数据创建一个相同类型的对象吗?如果您使用创建空对象(空白画布)并复制属性 - 我们基本上不会做同样的事情吗? – Biscuit128 2013-03-21 08:50:00

1

从你的问题我猜你需要深拷贝的对象。如果是这种情况,请不要使用clone方法,因为它已经在oracle docs中指定它提供浅拷贝的关联对象。我对BeanUtils.copyProperties API没有足够的了解。
以下是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"); 
     } 

    } 
} 
4

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

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

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

+1

春季4.x之后,它确实比较了soruce和目标豆的原始类型。所以,要小心使用BeanUtils复制属性。请记住,您具有可以从源到目标分配的相同的基本类型 – 2016-02-17 07:11:47

0

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

另一方面BeanUtils.copyProperties负责处理所有事情。 它减少你的努力。

2

我认为你正在寻找一个深层次的副本。你可以在util类中使用下面的方法,并将它用于任何类型的对象。

public static <T extends Serializable> 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); 
    } 
} 
相关问题