java容器類分析:Collection,List,ArrayList,
1、 Iterable 與 Iterator
Iterable 是個介面,實現此介面使集合對象可以通過迭代器遍曆自身元素.
public interface Iterable<T>
| 修飾符和傳回值 |
方法名 |
描述 |
| Iterator<T> |
iterator() |
返回一個內部元素為T類型的迭代器 |
| default void |
forEach(Consumer<? super T> action) |
對內部元素進行遍曆,並對元素進行指定的操作 |
| default Spliterator<T> |
spliterator() |
建立並返回一個可分割迭代器 |
第一個介面iterator()是jdk1.5引入的,需要子類實現一個內部迭代器Iterator遍曆元素。
後兩個介面是JDK1.8後新添加的,forEach(Consumer action)是為了方便遍曆操作集合內的元素,spliterator()則提供了一個可以並行遍曆元素的迭代器,以適應現在cpu多核時代並行遍曆的需求.
其中我們可以看下default修飾符,這也是Java 8後新出現的,我們知道,如果我們給一個介面新添加一個方法,那麼所有他的具體子類都必須實現此方法,為了能給介面拓展新功能,而又不必每個子類都要實現此方法,Java 8新加了default關鍵字,被其修飾的方法可以不必由子類實現,並且由dafault修飾的方法在介面中有方法體,這打破了Java之前對介面方法的規範.
Iterator 為迭代器類,用於遍曆容器。
public interface Iterator<E>
| 修飾符和傳回值 |
方法名 |
描述 |
| boolean |
hasNext() |
判斷迭代器所指元素是否為最後一個 |
| E |
next() |
下一個元素 |
| default Void |
remove() |
移除迭代器只想的當前元素 |
| default Void |
forEachRemaining(Consumer<? super E> action) |
遍曆迭代器指向元素後面的所有元素 |
AbstartList中實現了Iterator類作為List內部的迭代器,用於訪問內部元素,其代碼如下:
1 private class Itr implements Iterator<E> { 2 /** 3 * Index of element to be returned by subsequent call to next. 4 */ 5 int cursor = 0; 6 7 /** 8 * Index of element returned by most recent call to next or 9 * previous. Reset to -1 if this element is deleted by a call 10 * to remove. 11 */ 12 int lastRet = -1; 13 14 /** 15 * The modCount value that the iterator believes that the backing 16 * List should have. If this expectation is violated, the iterator 17 * has detected concurrent modification. 18 */ 19 int expectedModCount = modCount; 20 21 public boolean hasNext() { 22 return cursor != size(); 23 } 24 25 public E next() { 26 checkForComodification(); 27 try { 28 int i = cursor; 29 E next = get(i); 30 lastRet = i; 31 cursor = i + 1; 32 return next; 33 } catch (IndexOutOfBoundsException e) { 34 checkForComodification(); 35 throw new NoSuchElementException(); 36 } 37 } 38 39 public void remove() { 40 if (lastRet < 0) 41 throw new IllegalStateException(); 42 checkForComodification(); 43 44 try { 45 AbstractList.this.remove(lastRet); 46 if (lastRet < cursor) 47 cursor--; 48 lastRet = -1; 49 expectedModCount = modCount; 50 } catch (IndexOutOfBoundsException e) { 51 throw new ConcurrentModificationException(); 52 } 53 } 54 55 final void checkForComodification() { 56 if (modCount != expectedModCount) 57 throw new ConcurrentModificationException(); 58 } 59 } 60 View Code2、Collection
Collection 是容器類的介面,裡面可以存放很多Elements,很多容器都實現了該介面。
public interface Collection<E> extends Iterable<E>
| 修飾符和傳回值 |
方法名 |
描述 |
| int |
size() |
判斷容器的大小 |
| boolean |
isEmpty() |
判空 |
| boolean |
contains(Object o) |
是否包含某元素 |
| Object[] |
toArray() |
轉化為數組 |
| <T> T[] |
toArray(T[] a) |
將容器中所有元素拷貝到a中,如果a不夠大,則拷貝到返回的數組中。(見AbstactCollection中實現) |
| boolean |
add(E e) |
添加元素 |
| boolean |
remove(Object o) |
移除容器中第一個出現Object對象,如果Object為null,則移除第一個出現的null。如果沒有Object對象返回false |
| boolean |
containsAll(Collection<?> c) |
包含c中所有元素 |
| boolean |
addAll(Collection<? extends E> c); |
將c中所有元素添加到容器中 |
| boolean |
removeAll(Collection<?> c) |
如果容器中包含c中的元素,刪除。(調用remove(Object)) |
| default boolean |
removeIf(Predicate<? super E> filter) |
移除所有合格元素(JDK1.8中引入) |
| boolean |
retainAll(Collection<?> c) |
保留在c中出現的元素,其它全部移除 |
| boolean |
clear() |
|
| boolean |
equals(Object o) |
與o中所有元素都相等則相等 |
| int |
hashCode() |
c1.equals(c2) 那麼他們的hashCode()一定相等,反之不成立 |
| default Spliterator<E> |
spliterator() |
在所有元素之上建立一個Spliterator |
| default Stream<E> |
stream() |
|
| default Stream<E> |
parallelStream() |
|
上述很多函數的實現可以參考 AbstactList中的實現。
3. List
List是一個介面,繼承了Collection中的所有介面,並且添加了自身相關介面和具體實現。
由可以看出,Collection分成了三個分支,List就是其中一個,下面我們具體分析一下增加的介面。
public interface List<E> extends Collection<E>
| 修飾符和傳回值 |
方法名 |
描述 |
| |
Collection中的所有介面 |
|
| default void |
replaceAll(UnaryOperator<E> operator) |
將運算操作後的結果替換List中原有元素 |
| default void |
sort(Comparator<? super E> c) |
將List中所有元素排序 |
| E |
get(int index); |
|
| E |
set(int index, E element) |
|
| E |
remove(int index) |
|
| int |
indexOf(Object o) |
o在List中第一次出現的位置 |
| int |
lastIndexOf(Object o) |
o在List中最後一次出現的位置 |
| ListIterator<E> |
listIterator() |
擷取List的迭代器 |
| ListIterator<E> |
listIterator(int index) |
擷取從某個位置開始的迭代器,index為迭代器起始位置 |
| List<E> |
subList(int fromIndex, int toIndex) |
子List |
上表可以看出,增加了 和index相關的介面,根據index對List進行的get、set、remove等操作。另一類添加的介面是ListIteator相關的,擷取List的迭代器。
3.1 ListIterator
public interface ListIterator<E> extends Iterator<E>
ListIterator 不光包含Iterator中的三個介面還增加了作為一個List迭代器應該有的介面,如 next(),previous()等
| 修飾符和傳回值 |
方法名 |
描述 |
| |
Iterator中的所有介面 |
|
| boolean |
hasNext() |
|
| E |
next() |
|
| boolean |
hasPrevious() |
|
| E |
previous() |
|
| int |
nextIndex() |
|
| int |
previousIndex() |
|
| void |
remove() |
刪除next()返回元素 |
| void |
set(E e) |
替換next()返回的元素 |
| void |
add(E e) |
在nextIndex()後插入元素 |
首先需要明確ListIterator迭代器的作用:
注意,迭代器 沒有當前所在元素一說,它只有一個遊標( cursor )的概念,這個遊標總是在元素之間,比如這樣:
迭代器的初始位置:
調用next()後迭代器的位置
調用 previous() 遊標就會回到之前位置。當向後遍曆完元素,遊標就會在元素 N 的後面
也就是說長度為 N 的集合會有 N+1 個遊標的位置。
3.2 AbstractCollection / AbstractList
在上面的繼承關係圖中並沒有顯示出AbstractCollect和AbstractList的存在,但是在閱讀源碼的時候經常遇到這兩個類,下面講一下這兩個類的作用。
首先需要明確的一點是AbstractCollect和AbstractList都是抽象類別而不是介面,它們分別實現了Collection和List介面中的部分函數。這樣繼承者直接繼承AbstractXXXX 而不需要自己重複實現裡面的所有介面。這兩個抽象類別抽離了公用部分,進行了實現,減少後續類的工作量。
ArrayList 和LinkedList都直接或者間接繼承了AbstartList類。為這兩個類的繼承關係:
具體這兩個類裡面實現了哪些介面,請自己閱讀源碼不再講解。
3.3 ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable我們看到ArrayList的定義的時候很可能會出現一個疑問,為什麼它已經繼承了AbstractList了還需要去實現List<E>介面? 答案是,後面的List<E>可以去掉,這裡只是讓閱讀者明白ArrayList是個List。 終於好不容易到了開發人員常用的類了,有點竊喜:transient Object[] elementData;這個很重要的成員變數elementData數組用來存放ArrayList中的元素,當第一個元素添加進來後,它的預設長度變為10。(java中“transient”關鍵字修飾的成員變數在類序列化的過程中不會被持久化到檔案中,保證該成員變數儲存資訊的安全。)
ArrayList的建構函式中可以直接指定elementData數組的長度,那麼問題來了,當數組已經完全被佔用再向ArrayList中添加元素時,如何再分配更大長度的數組?如何把舊資料拷貝到新數組中?答案見下面這段源碼
1 private void grow(int minCapacity) { //最少需要的容量 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + (oldCapacity >> 1); // 分配最小容量的 1.5倍 5 if (newCapacity - minCapacity < 0) 6 newCapacity = minCapacity; 7 if (newCapacity - MAX_ARRAY_SIZE > 0) 8 newCapacity = hugeCapacity(minCapacity); // 最大容量比較(Inter.MAX_VALUE) 9 // minCapacity is usually close to size, so this is a win: 10 elementData = Arrays.copyOf(elementData, newCapacity); // 將舊資料拷貝到新數組中 11 }
其它介面不再細說。
參考:https://www.cnblogs.com/bushi/p/6647006.html
https://www.jianshu.com/p/047e33fdefd2