2013-03-21 130 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); 
    } 
} 
相關問題