Java中如何複製集合——ArrayList和HashSet深拷貝

來源:互聯網
上載者:User

標籤:

  編程人員經常誤用各個集合類提供的拷貝建構函式作為複製ListSetArrayListHashSet或者其他集合實現的方法。需要記住的是,Java集合的拷貝建構函式只提供淺拷貝而不是深拷貝,這意味著儲存在原始List和複製List中的對象是相同的,指向Java堆記憶體中相同的位置。增加了這個誤解的原因之一是對於不可變對象集合的淺複製。由於不可變性,即使兩個集合指向相同的對象是可以的。字串池包含的字串就是這種情況,更改一個不會影響到另一個。使用ArrayList的拷貝建構函式建立僱員List的拷貝時就會出現問題,Employee類不是不可變的。在這種情況下,如果原創組合修改了僱員資訊,這個變化也將反映到複製集合。同樣如果複製集合僱員資訊發生變化,原創組合也會被更改。絕大多數情況下,這種變化不是我們所希望的,複製對象應該與原始對象獨立。解決這個問題的方法是深複製集合,深複製將遞迴複製對象直到基礎資料型別 (Elementary Data Type)或者不可變類。本文將瞭解一下深拷貝ArrayList或者HashSet等集合類的一種方法。如果你瞭解深拷貝與淺拷貝之間的區別,那麼理解集合深複製的方法就會很簡單。

Java集合的深複製

下面例子有一個Employee集合,Employee是可變對象,成員變數namedesignation。它們儲存在HashSet中。使用java.util.Collection介面的addAll()方法建立集合拷貝。然後修改儲存在原創組合每個Employee對象的designation值。理想情況下這個改變不會影響複製集合,因為複製集合和原創組合應該相互獨立,但是複製集合也被改變了。修正這個問題的方法是對儲存在Collection類中的元素深複製。

 1 /** 2  *  3  * @ClassName: CollectionCloningTest 4  * TODO 5  * @author xingle 6  * @date 2015-3-20 下午3:32:22 7  */ 8 public class CollectionCloningTest { 9     10     public static void main(String[] args){11         ArrayList<Employee> org = new ArrayList<Employee>();12         org.add(new Employee("Joe", "Manager")); 13         org.add(new Employee("Tim", "Developer")); 14         org.add(new Employee("Frank", "Developer")); 15                16         Collection<Employee> copy = new HashSet<>(org);                17         18         System.out.println("原來的集合: "+org);19         System.out.println("複製的集合: "+copy);20         21         Iterator<Employee> orgItr = org.iterator();22         while(orgItr.hasNext()){ 23             orgItr.next().setDesignation("staff"); 24             25         }26 27         System.out.println("修改後原來的集合: "+org);28         System.out.println("修改後複製的集合: "+copy);29     }30 31 }32 33 34 class Employee { 35     private String name; 36     private String designation; 37      38     public Employee(String name, String designation) { 39         this.name = name; 40         this.designation = designation; 41     } 42      43     public String getDesignation() { 44         return designation; 45     } 46  47     public void setDesignation(String designation) { 48         this.designation = designation; 49     } 50  51     public String getName() { 52         return name; 53     } 54  55     public void setName(String name) { 56         this.name = name; 57     } 58  59     @Override60     public String toString() { 61         return String.format("%s: %s", name, designation ); 62     } 63 64 }

執行結果:

 

可以看到改變原始CollectionEmployee對象(改變designation為”staff“)在複製集合中也有所反映,因為複製是淺拷貝,指向堆中相同的Employee對象。為了修正這個問題,需要遍曆集合,深複製Employee對象,在這之前,要重寫Employee對象的clone方法。

1)Employee實現Cloneable介面
2)為Employee類增加下面的clone()方法

3)不使用拷貝建構函式,使用下面的代碼來深拷貝集合

 1 public class CollectionCloningTest { 2      3     public static void main(String[] args){ 4         ArrayList<Employee> org = new ArrayList<Employee>(); 5         org.add(new Employee("Joe", "Manager"));  6         org.add(new Employee("Tim", "Developer"));  7         org.add(new Employee("Frank", "Developer"));  8                 9        //Collection<Employee> copy = new HashSet<>(org);10        Collection<Employee> copy = new HashSet<Employee>(org.size()); 11                 12         13         System.out.println("原來的集合: "+org);14         System.out.println("複製的集合: "+copy);15         16         Iterator<Employee> orgItr = org.iterator();17         while(orgItr.hasNext()){ 18             //orgItr.next().setDesignation("staff"); 19             copy.add(orgItr.next().clone());   20             21         }22         23 24         Iterator<Employee> orgItr2 = org.iterator();25         while(orgItr2.hasNext()){ 26             orgItr2.next().setDesignation("staff"); 27         } 28         System.out.println("修改後原來的集合: "+org);29         System.out.println("修改後複製的集合: "+copy);30     }31 32 }33 34 35 class Employee implements Cloneable{ 36     private String name; 37     private String designation; 38      39     public Employee(String name, String designation) { 40         this.name = name; 41         this.designation = designation; 42     } 43      44     public String getDesignation() { 45         return designation; 46     } 47  48     public void setDesignation(String designation) { 49         this.designation = designation; 50     } 51  52     public String getName() { 53         return name; 54     } 55  56     public void setName(String name) { 57         this.name = name; 58     } 59  60     @Override61     public String toString() { 62         return String.format("%s: %s", name, designation ); 63     } 64     65     @Override66     protected Employee clone(){67         try {68             Employee result = (Employee) super.clone();69             return result;70         } catch (CloneNotSupportedException e) {71              throw new RuntimeException(e); // won‘t happen 72         }73         74     }75 }

 

執行結果:

可以看到複製集合和原創組合相互獨立,它們指向不同的對象。

這就是Java中如何複製集合的內容。現在我們知道拷貝建構函式或者ListSet等各種集合類的addAll()方法僅僅建立了集合的淺拷貝,而且原創組合和複製集合指向相同的對象。為避免這個問題,應該深複製集合,遍曆集合複製每個元素。儘管這要求集合中的對象必須支援深複製操作。

Java中如何複製集合——ArrayList和HashSet深拷貝

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.