2017-07-07 43 views
25

是否有可能找出一些清單是否爲固定大小? 我的意思是,例如此代碼:是否可以找出某個列表是否爲固定大小?

String[] arr = {"a", "b"}; 
List<String> list = Arrays.asList(array); 

返回固定大小List由數組支持。但是,如果List是固定大小或沒有嘗試添加/刪除元素並捕獲異常,是否有可能以編程方式理解?例如:

try { 
    list.add("c"); 
} 
catch(UnsupportedOperationException e) { 
    // Fixed-size? 
} 
+0

爲什麼你不能使用異常? – 2017-07-07 16:19:28

+6

@RC。他沒有說他不能,但如果有另一種方法去做,它不是理想的。例外情況緩慢並且出現異常情況。 – Michael

+7

關閉選民,請解釋如何不清楚。我完全理解他在問什麼。 – Michael

回答

6

是否有可能找出是否某些列表是固定大小與否?

理論上 - 不是。固定大小是實現列表類的一個新特性。您只能通過嘗試添加元素來確定列表是否具有該屬性。

並注意一個簡單的行爲測試不能可靠地區分固定大小的列表和有界列表,或者是永久性的列表或暫時只讀。


在實踐中,一個固定的大小的列表將通常具有不同的類,以通常的一個。您可以測試對象的類以查看它或不是特定的類。因此,如果您瞭解在您的代碼庫中用於實現固定大小列表將是,那麼您可以測試某個特定列表是否爲固定大小。

例如,Arrays.asList(...)方法返回一個List對象,其實際類別爲java.util.Arrays.ArrayList。這是一個私有嵌套類,但您可以使用反射查找它,然後使用Object.getClass().equals(...)來測試它。

但是,這種方法是脆弱的。如果修改了Arrays的實現,或者您也開始使用其他形式的固定大小列表,那麼您的代碼可能會中斷。

14

String[]創建的列表由

List<String> list = Arrays.asList(array); 

將具有Arrays作爲封閉類,而一個由例如new ArrayList()不會有封閉類創建。所以下面應該工作,以檢查清單製作調用Arrays.toList()的結果:

static <T> boolean wasListProducedAsAResultOfCallingTheFunctionArrays_asList(List<T> l) { 
    return Arrays.class.equals(l.getClass().getEnclosingClass()); 
} 

要注意的是這種方法依賴於無證行爲。如果他們將另一個嵌套的List子類添加到Arrays類,它將會中斷。

+2

好的。儘管如此,'isFixedSize'對於那個函數有點用詞不當。 – Michael

+0

@Michael謝謝。你心目中有更好的名字嗎?隨意編輯:-) – baao

+10

[也許'wasListProducedAsAResultOfCallingTheFunctionArrays_asList'](https://martinfowler.com/bliki/TwoHardThings.html)?? – Michael

2

列表API是相同的,無論列表是否擴張與否,這一點是很deliberate

List API中也沒有任何內容允許您查詢它來確定此功能。

通過反射您不能完全可靠地確定此信息,因爲您將取決於實施的內部細節,並且因爲存在無限數量的可能固定大小的類。例如,除Arrays.asList之外,還有Arrays.asList().subList,這恰好返回不同的類。在基本列表周圍也可以有包裝,如Collections.checkedList,Collections.synchronizedListCollections.unmodifiableList。還有其他固定大小的列表:Collections.emptyList,Collections.singletonListCollections.nCopies。在標準庫之外,有些東西像番石榴的ImmutableList。通過擴展AbstractList(對於只需實現size()get(int)方法的固定大小列表)手動滾動列表以獲取某些內容也很不起眼。

即使您檢測到您的列表不是固定大小,規範List.add也允許它拒絕其他原因的元素。例如,Collections.checkedList包裝器爲不需要類型的元素投擲ClassCastException

即使你知道你的列表是可擴展的,並且允許任意元素,這並不意味着你想使用它。也許它是同步的,或者不同步的,或者不可序列化的,或者它是一個慢速鏈表,或者有一些你不想要的其他質量。

如果您想要控制列表的類型,可變性,可序列化或線程安全性,或者您想確保沒有其他代碼保留對其的引用,則練習是您創建一個新的你自己。當不必要的時候這樣做並不昂貴(memcopies的速度非常快),並且它可以讓你更確切地推斷你的代碼在運行時會真正做到的。如果您真的想避免創建不必要的副本,請嘗試使用列入白名單,而不是列入黑名單列表類。例如:

if (list.getClass() != ArrayList.class) { 
    list = new ArrayList<>(list); 
} 

(注:使用getClass代替instanceof,因爲instanceof也爲ArrayList任何奇怪的子類是真實的)

+0

非常棒的答案。 – Michael

0

在Java中,9不可改變的集合,但有仍然沒有常見的@Immutable註釋或例如我們可以查詢以獲取此信息的通用標記接口。

我能想到的最簡單的方法是簡單地獲取類這樣的實例的名稱:

String nameList = List.of(1, 2, 3).getClass().getName(); 
System.out.println(nameList.contains("Immutable")); 

但仍然依賴於內部的細節,因爲它查詢的通用類的名稱ImmutableCollections,這是不公開的,顯然可以更改,恕不另行通知。

相關問題