2010-09-06 78 views
4

通過查看Collections類的代碼,我知道當我們使用方法unmodifiableList(List list)unmodifiableCollection(Collection c)時,它不會創建新對象,但會返回同一對象的引用並覆蓋可以修改該對象的方法List [addaddallremoveretainAll ...]
所以我跑這個測試:如果我們有原始的清單,爲什麼我們可以更改不可修改的清單?

List modifiableList = new ArrayList(); 
modifiableList.add (1); 
List unmodifiableList = Collections.unmodifiableList(modifiableList); 
// unmodifiableList.add(3); // it will throw the exception 
modifiableList.add (2);  
System.out.println(unmodifiableList); 

結果是[ 1,2 ]
現在的重點是爲什麼它指的是同一個對象?爲什麼它不創建一個新的對象?

+3

什麼你正在尋找被稱爲「不可變列表。」番石榴有這個。 (http://guava-libraries.googlecode.com) – 2010-09-09 14:02:33

+0

Google Guava,[ImmutableCollections](https://github.com/google/guava/wiki/ImmutableCollectionsExplained)< - 更新了doc鏈接。 – 2015-09-02 21:53:35

回答

9

(在底部的queston的答案)

當你創建一個不可修改的列表,目的是它不應該被比你其他人進行修改- 即API的客戶。

方法unmodifiableList(..)創建UnmodifiableList類型的新對象(但這不是一個公共類),用於獲取原始列表,以及所有方法委託給它除了這將修改它的方法。

的一點是,如文檔中所述:

返回指定列表的修改視圖。此方法允許模塊爲用戶提供對內部列表的「只讀」訪問權限。

所以,一個例子:你有你的API已經檢測並能夠操作設備的List,你想給他們你的API的客戶端。但他不應該更換他們。所以,你有兩個選擇:

  • 給他你的List的深層副本,這樣即使他修改它,這不會改變列表
  • 給他一個不可修改的集合 - 他不能修改它,並且您不需要創建新的集合。

而現在這裏來回答你的問題的標題 - 的不可修改的列表是原始集合的視圖。所以如果你需要添加一個新的項目 - 比方說,你發現了一個剛剛插入的新設備,客戶端將能夠在他們的不可修改視圖中看到它。

+0

這是否僅用於我們獲得相同列表參考的性能? – 2010-09-06 10:32:42

+0

這裏沒有涉及性能_directly_。只有您可能希望禁用API的客戶端對列表的修改。看到我的更新,看看性能如何受到影響_indirectly_ – Bozho 2010-09-06 10:33:22

+0

「它不應該被修改」 - 我建議你添加「,甚至沒有其他地方!」 – 2010-09-06 10:34:30

3

現在的關鍵是爲什麼它指的是 到同一個對象?爲什麼不要 創建一個新的對象?

表現。它只是不能縮放來製作完整的副本。做一個完整的副本顯然是不實際的,這將是一個線性時間操作。另外,正如其他人已經指出的那樣,重點是您可以傳遞不可修改列表的引用,而不必擔心它會發生變化。這對多線程程序非常有用。

0

我相信祕密在於實現細節... Collection.unmodifiableList()只會給你修飾的可修改列表。我的意思是不可修改的列表包含內部對可修改列表的引用。

2

從技術文檔:

public static List unmodifiableList(List list)

返回無法修改視圖指定列表的。此方法允許模塊爲用戶提供「只讀」訪問內部列表。將返回列表上的查詢操作「讀取」到指定列表中,並嘗試修改返回的列表,無論是直接還是通過其迭代器,都會導致UnsupportedOperationException。

-2
  1. 你應該去創建一個列表的新對象,只有當原來的目標要被改變,你需要一個備份,當有人破壞它,U可以通過新對象代替。

  2. 要創建一個不可修飾的對象,我將包裝原始對象並防止添加,通過拋出異常來刪除。但是你知道,我可以改變列表中的每個對象。例如,如果你在一個不可修改的列表中有一個人物對象,我仍然可以改變列表中的人物對象的名字。

0

The accepted Answer作者Bozho是正確的。這裏有更多信息,示例代碼和建議的替代方法。

的unmodifiableList是背靠原版

,在Collections實用類unmodifiableList方法不創建一個新的列表,它會創建一個假名單由原始列表支持。任何通過「不可修改」對象進行的添加或刪除嘗試都將被阻止,因此名稱將達到其目的。但事實上,正如你所顯示的那樣,原始列表可以被修改,並同時影響我們的次要的不太不可修改的列表。

這是類文檔中列明:

返回指定列表的不可修改視圖。此方法允許模塊爲用戶提供對內部列表的「只讀」訪問權限。將返回列表上的查詢操作「讀取」到指定列表中,並嘗試修改返回的列表,無論是直接還是通過其迭代器,都會導致UnsupportedOperationException。

第四個字是關鍵:view。新的列表對象不是新鮮的列表。這是一個覆蓋。就像tracing papertransparency film在圖紙上停止您在圖紙上標記,它不會阻止您從底層修改原始圖紙。

道德故事:不要使用Collections.unmodifiableList來製作列表的防禦副本。

同上Collections.unmodifiableMap,Collections.unmodifiableSet等等。

下面是演示該問題的另一個示例。

String dog = "dog"; 
String cat = "cat"; 
String bird = "bird"; 

List<String> originalList = new ArrayList<>(3); 
originalList.add(dog); 
originalList.add(cat); 
originalList.add(bird); 

List<String> unmodList = Collections.unmodifiableList(originalList); 
System.out.println("unmod before: " + unmodList); // Yields [dog, cat, bird] 
originalList.remove(cat); // Removing element from original list affects the unmodifiable list? 
System.out.println("unmod after: " + unmodList); // Yields [dog, bird] 

谷歌番石榴

取而代之的Collections類,用於防禦式編程我建議使用Google Guava庫及其ImmutableCollections設施。

您可以創建一個新的列表。

public static final ImmutableList<String> ANIMALS = ImmutableList.of(
     dog, 
     cat, 
     bird); 

或者您可以製作現有列表的防禦副本。在這種情況下,你會得到一個新的單獨列表。從原始列表中刪除而不是會影響(縮小)不可變列表。

ImmutableList<String> ANIMALS = ImmutableList.copyOf(originalList); // defensive copy! 

但要記住,而收集的自己的定義是不同的,所包含的對象由最初的名單和新的不可變列表都共享。在製作防禦性副本時,我們不會重複「狗」對象。只有一個狗對象留在內存中,這兩個列表都包含指向同一只狗的引用。如果「狗」對象中的屬性被修改,兩個集合都指向同一個單獨的狗對象,因此兩個集合都會看到狗的新屬性值。

0

我發現做到這一點的方法之一是

List unmodifiableList = Collections.unmodifiableList(new ArrayList(modifiableList)); 

List<String> strings = new ArrayList<String>(); 
     // unmodifiable.add("New string"); 
     strings.add("Aha 1"); 
     strings.add("Aha 2"); 
     List<String> unmodifiable = Collections.unmodifiableList(strings); 
     List<String> immutableList = Collections.unmodifiableList(new ArrayList<>(strings)); 
     // Need some way to fix it so that Strings does not Modify 
     strings.add("Aha 3"); 
     strings.add("Aha 4"); 

     strings.remove(0); 

     for (String str : unmodifiable) { 
      System.out.println("Reference Modified :::" + str); 
     } 

     for (String str : immutableList) { 
      System.out.println("Reference Modified :::" + str); 
     } 
相關問題