每天都在用ArrayList,你會用AbstractList嗎

為什麼有時候要避免使用ArrayList

在工程中,經常能看到類似如下代碼:

final List<string> list1 = ...;/<string>

final List<string> list2 = ...;final List<string> results = new ArrayList<>(list1.size() + list2.size());/<string>/<string>

results.addAll(list1);

results.addAll(list2);

return results;

其功能非常簡單,將兩個list合併成一個list,而完成這個功能非常簡單,就是使用一個ArrayList,將兩個list中的元素全部加入到這個list中。

但是這樣做的問題在於以下兩點:

1. 時間開銷大,需要將兩個list中的元素全部加入到新的list中

2. 需要創建額外的數組空間,甚至在加入第二個list時,ArrayList需要擴容

可以看到ArrayList中的代碼:

每天都在用ArrayList,你會用AbstractList嗎

每天都在用ArrayList,你會用AbstractList嗎

這兩段ArrayList中的代碼並沒有問題,只不過在這樣的場景下並不是最優的。

我們再看看我們常用的Arrays.asList()方法是如何實現的:

每天都在用ArrayList,你會用AbstractList嗎

可以看到,Arrays.asList()方法中創建了一個ArrayList,但是此ArrayList並不是java.util.ArrayList,而是Arrays的一個靜態類部類,從截圖中的代碼可以看出,Arrays.asList()方法沒只有O(1)的時間開銷,並且沒有創建額外的數組。

回到前面的例子,我們怎麼將兩個list合併成一個list並返回呢,類似的,我們可以使用AbstractList:

每天都在用ArrayList,你會用AbstractList嗎

很多類似的場景都非常適合使用AbstractList而不是ArrayList,比如Guava中的Lists..asList()的代碼:

每天都在用ArrayList,你會用AbstractList嗎

AbstractList

AbstractList類是專為繼承而設計的類,其中提供了get和size兩個抽象方法,子類最小隻需要實現這兩個方法即可,但這樣創建出來的List是不支持修改的,我們可以看看ArrayList的源碼,其中的set/add/remove方法如下:

每天都在用ArrayList,你會用AbstractList嗎

如果想要通過AbstractList派生出來的List支持修改,需要覆蓋這三個方法

AbstractList作為List的抽象實現,其脫離了具體的數據結構,提供了不同類型的數據結構實現的List所需要的通用方法,在AbstractList提供的默認實現中,在特定場景下可能會有性能上的不足,比如addAll方法:

每天都在用ArrayList,你會用AbstractList嗎

如果是鏈表結構的List,此方法性能將非常低,時間開銷會是O(n*m),n和m是兩個list的長度。而LinkedList中則選擇了覆蓋此方法,利用鏈表的尾插法重新實現了此方法從而保證了性能。同樣ArrayList也重新實現了addAll方法,前文中可以看到,通過複製數組的方式代替遍歷的方式

AbstractCollection

最後看看AbstractCollection,AbstractCollection提供了Collection的抽象實現,Collection接口包含Set接口和List接口,因此Collection中無法判斷出集合是有序的(List)還是無序的(Set),因此AbstractCollection中沒有提供迭代器的默認實現,而AbstractList中提供了迭代器的默認實現:

每天都在用ArrayList,你會用AbstractList嗎

而在AbstractCollection接口提供的方法實現基本上都是基於迭代器的:

每天都在用ArrayList,你會用AbstractList嗎

因此在AbstractCollection的子類中,也可能會出現AbstractCollection提供的方法有性能優化的空間,比如把迭代器替換成arraycopy等

AbstractSet

最後看一下AbstractSet類,同樣,AbstractSet中並沒有提供迭代器的默認實現,其中只是對removeAll做了重新實現,並覆蓋了hashcode和equals

每天都在用ArrayList,你會用AbstractList嗎


分享到:


相關文章: