java容器类1:Collection,List,ArrayList,LinkedList深入解读
1、 Iterable 與 Iterator
Iterable 是個(gè)接口,實(shí)現(xiàn)此接口使集合對(duì)象可以通過(guò)迭代器遍歷自身元素.
public interface Iterable<T>
| 修飾符和返回值 | 方法名 | 描述 |
| Iterator<T> | iterator() | 返回一個(gè)內(nèi)部元素為T類型的迭代器 |
| default void | forEach(Consumer<? super T> action) | 對(duì)內(nèi)部元素進(jìn)行遍歷,并對(duì)元素進(jìn)行指定的操作 |
| default Spliterator<T> | spliterator() | 創(chuàng)建并返回一個(gè)可分割迭代器 |
第一個(gè)接口iterator()是jdk1.5引入的,需要子類實(shí)現(xiàn)一個(gè)內(nèi)部迭代器Iterator遍歷元素。
后兩個(gè)接口是JDK1.8后新添加的,forEach(Consumer action)是為了方便遍歷操作集合內(nèi)的元素,spliterator()則提供了一個(gè)可以并行遍歷元素的迭代器,以適應(yīng)現(xiàn)在cpu多核時(shí)代并行遍歷的需求.
其中我們可以看下default修飾符,這也是Java 8后新出現(xiàn)的,我們知道,如果我們給一個(gè)接口新添加一個(gè)方法,那么所有他的具體子類都必須實(shí)現(xiàn)此方法,為了能給接口拓展新功能,而又不必每個(gè)子類都要實(shí)現(xiàn)此方法,Java 8新加了default關(guān)鍵字,被其修飾的方法可以不必由子類實(shí)現(xiàn),并且由dafault修飾的方法在接口中有方法體,這打破了Java之前對(duì)接口方法的規(guī)范.
Iterator 為迭代器類,用于遍歷容器。
public interface Iterator<E>
| 修飾符和返回值 | 方法名 | 描述 |
| boolean | hasNext() | 判斷迭代器所指元素是否為最后一個(gè) |
| E | next() | 下一個(gè)元素 |
| default Void | remove() | 移除迭代器指向的當(dāng)前元素 |
| default Void | forEachRemaining(Consumer<? super E> action) | 遍歷迭代器指向元素后面的所有元素 |
AbstartList中實(shí)現(xiàn)了Iterator類作為L(zhǎng)ist內(nèi)部的迭代器,用于訪問(wèn)內(nèi)部元素,其代碼如下:
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 } 602、Collection
Collection 是容器類的接口,里面可以存放很多Elements,很多容器都實(shí)現(xiàn)了該接口。
public interface Collection<E> extends Iterable<E>
| 修飾符和返回值 | 方法名 | 描述 |
| int | size() | 判斷容器的大小 |
| boolean | isEmpty() | 判空 |
| boolean | contains(Object o) | 是否包含某元素 |
| Object[] | toArray() | 轉(zhuǎn)化為數(shù)組 |
| <T> T[] | toArray(T[] a) | 將容器中所有元素拷貝到a中,如果a不夠大,則拷貝到返回的數(shù)組中。(見AbstactCollection中實(shí)現(xiàn)) |
| boolean | add(E e) | 添加元素 |
| boolean | remove(Object o) | 移除容器中第一個(gè)出現(xiàn)Object對(duì)象,如果Object為null,則移除第一個(gè)出現(xiàn)的null。如果沒有Object對(duì)象返回false |
| boolean | containsAll(Collection<?> c) | 包含c中所有元素 |
| boolean | addAll(Collection<? extends E> c); | 將c中所有元素添加到容器中 |
| boolean | removeAll(Collection<?> c) | 如果容器中包含c中的元素,刪除。(調(diào)用remove(Object)) |
| default boolean | removeIf(Predicate<? super E> filter) | 移除所有符合條件的元素(JDK1.8中引入) |
| boolean | retainAll(Collection<?> c) | 保留在c中出現(xiàn)的元素,其它全部移除 |
| boolean | clear() | |
| boolean | equals(Object o) | 與o中所有元素都相等則相等 |
| int? | hashCode() | c1.equals(c2) 那么他們的hashCode()一定相等,反之不成立? |
| default Spliterator<E> | spliterator() | 在所有元素之上創(chuàng)建一個(gè)Spliterator |
| default Stream<E> | stream() | |
| default Stream<E> | parallelStream() |
上述很多函數(shù)的實(shí)現(xiàn)可以參考 AbstactList中的實(shí)現(xiàn)。
3. List
List是一個(gè)接口,繼承了Collection中的所有接口,并且添加了自身相關(guān)接口和具體實(shí)現(xiàn)。
由上圖可以看出,Collection分成了三個(gè)分支,List就是其中一個(gè),下面我們具體分析一下增加的接口。
public interface List<E> extends Collection<E>
| 修飾符和返回值 | 方法名 | 描述 |
| Collection中的所有接口 | ||
| default void | ?replaceAll(UnaryOperator<E> operator) | 將運(yùn)算操作后的結(jié)果替換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中第一次出現(xiàn)的位置 |
| int | lastIndexOf(Object o) | o在List中最后一次出現(xiàn)的位置 |
| ListIterator<E> | listIterator() | 獲取List的迭代器 |
| ListIterator<E> | listIterator(int index) | 獲取從某個(gè)位置開始的迭代器,index為迭代器起始位置 |
| List<E> | subList(int fromIndex, int toIndex) | 子List |
上表可以看出,增加了 和index相關(guān)的接口,根據(jù)index對(duì)List進(jìn)行的get、set、remove等操作。另一類添加的接口是ListIteator相關(guān)的,獲取List的迭代器。
3.1 ListIterator
public interface ListIterator<E> extends Iterator<E>
ListIterator 不光包含Iterator中的三個(gè)接口還增加了作為一個(gè)List迭代器應(yīng)該有的接口,如 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迭代器的作用:
注意,迭代器 沒有當(dāng)前所在元素一說(shuō),它只有一個(gè)游標(biāo)( cursor )的概念,這個(gè)游標(biāo)總是在元素之間,比如這樣:
迭代器的初始位置:
調(diào)用next()后迭代器的位置
調(diào)用 previous() 游標(biāo)就會(huì)回到之前位置。當(dāng)向后遍歷完元素,游標(biāo)就會(huì)在元素 N 的后面
也就是說(shuō)長(zhǎng)度為 N 的集合會(huì)有 N+1 個(gè)游標(biāo)的位置。
3.2 AbstractCollection / AbstractList
??????? 在上面的繼承關(guān)系圖中并沒有顯示出AbstractCollect和AbstractList的存在,但是在閱讀源碼的時(shí)候經(jīng)常遇到這兩個(gè)類,下面講一下這兩個(gè)類的作用。
????? 首先需要明確的一點(diǎn)是AbstractCollect和AbstractList都是抽象類而不是接口,它們分別實(shí)現(xiàn)了Collection和List接口中的部分函數(shù)。這樣繼承者直接繼承AbstractXXXX 而不需要自己重復(fù)實(shí)現(xiàn)里面的所有接口。這兩個(gè)抽象類抽離了公共部分,進(jìn)行了實(shí)現(xiàn),減少后續(xù)類的工作量。
?????? ArrayList 和LinkedList都直接或者間接繼承了AbstartList類。下圖為這兩個(gè)類的繼承關(guān)系:
??????? 具體這兩個(gè)類里面實(shí)現(xiàn)了哪些接口,請(qǐng)自己閱讀源碼不再講解。
LinkedList中modCount和expectedModCount作用
在AbstractList中可以看到這兩個(gè)變量,它們用于表示List被修改的次數(shù),這其中包括了調(diào)用集合本身的add等方法等修改方法時(shí)進(jìn)行的修改和調(diào)用集合迭代器的修改方法進(jìn)行的修改。而expectedModCount則是表示迭代器對(duì)集合進(jìn)行修改的次數(shù)。
那么知道這兩個(gè)值有什么作用呢?
如果創(chuàng)建多個(gè)迭代器對(duì)一個(gè)集合對(duì)象進(jìn)行修改的話,那么就會(huì)有一個(gè)modCount和多個(gè)expectedModCount,且modCount的值之間也會(huì)不一樣,這就導(dǎo)致了moCount和expectedModCount的值不一致,從而產(chǎn)生異常。
https://www.cnblogs.com/zhangcaiwang/p/7131035.html
3.3 ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable我們看到ArrayList的定義的時(shí)候很可能會(huì)出現(xiàn)一個(gè)疑問(wèn),為什么它已經(jīng)繼承了AbstractList了還需要去實(shí)現(xiàn)List<E>接口? 答案是,后面的List<E>可以去掉,這里只是讓閱讀者明白ArrayList是個(gè)List。 終于好不容易到了開發(fā)者常用的類了,有點(diǎn)竊喜:transient Object[] elementData;這個(gè)很重要的成員變量elementData數(shù)組用來(lái)存放ArrayList中的元素,當(dāng)?shù)谝粋€(gè)元素添加進(jìn)來(lái)后,它的默認(rèn)長(zhǎng)度變?yōu)?0。(java中“transient”關(guān)鍵字修飾的成員變量在類序列化的過(guò)程中不會(huì)被持久化到文件中,保證該成員變量保存信息的安全。)
ArrayList的構(gòu)造函數(shù)中可以直接指定elementData數(shù)組的長(zhǎng)度,那么問(wèn)題來(lái)了,當(dāng)數(shù)組已經(jīng)完全被占用再向ArrayList中添加元素時(shí),如何再分配更大長(zhǎng)度的數(shù)組?如何把舊數(shù)據(jù)拷貝到新數(shù)組中?答案見下面這段源碼
其它接口不再細(xì)說(shuō)。
3.4 LinkedList
?
1 public class LinkedList<E> 2 extendsAbstractSequentialList<E>
3 implements List<E>, Deque<E>, Cloneable, java.io.Serializable作為一個(gè)鏈表類型,首先需要熟悉一下節(jié)點(diǎn)類:Node(LinkedList靜態(tài)內(nèi)部類)
1 private static class Node<E> { 2 E item; 3 Node<E> next; 4 Node<E> prev; 5 6 Node(Node<E> prev, E element, Node<E> next) { 7 this.item = element; 8 this.next = next; 9 this.prev = prev; 10 } 11 }在LinkedList中有三個(gè)主要成員變量:
- transient int size = 0;????? // 鏈表長(zhǎng)度
- transient Node<E> first;? // 鏈表的首節(jié)點(diǎn)
- transient Node<E> last;? // 鏈表的末節(jié)點(diǎn)
LinkedList構(gòu)造方法:
1 /** 2 * Constructs an empty list. 3 */ 4 public LinkedList() { 5 } 6 7 /** 8 * Constructs a list containing the elements of the specified 9 * collection, in the order they are returned by the collection's 10 * iterator. 11 * 12 * @param c the collection whose elements are to be placed into this list 13 * @throws NullPointerException if the specified collection is null 14 */ 15 public LinkedList(Collection<? extends E> c) { 16 this(); 17 addAll(c); 18 }clear()方法:遍歷LinkedList 置null
View Code
public E set(int index, E element):將某個(gè)Index指向的Node置變?yōu)閑lement
View Code
public void add(int index, E element):在鏈表的index位置添加一個(gè)節(jié)點(diǎn)
這里還有眾多的插入刪除等函數(shù),其主要思想還是對(duì)鏈表的操作(插入刪除等),詳情閱讀源碼。
3.5 ArrayList 與LinkedList 性能比較
兩種List的存儲(chǔ)結(jié)構(gòu)決定了兩者的性能:ArrayList以數(shù)組形式存儲(chǔ),LinkedList以鏈表形式存儲(chǔ)
ArrayList是以數(shù)組的形式存儲(chǔ)的,所以他的遍歷很快,可以根據(jù)index很快找到對(duì)應(yīng)元素。但是,ArrayList的插入和刪除操作較慢,如果需要在數(shù)組中插入一個(gè)元素或者刪除一個(gè)元素較麻煩。
LinkedList的索引操作較慢(需要遍歷列表才能找到對(duì)應(yīng)索引元素),但是它的插入和刪除操作效率高(只需要控制前后指針就能實(shí)現(xiàn)插入和刪除)。
參考:
https://www.cnblogs.com/bushi/p/6647006.html
https://www.jianshu.com/p/047e33fdefd2
總結(jié)
以上是生活随笔為你收集整理的java容器类1:Collection,List,ArrayList,LinkedList深入解读的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一步步编写操作系统 41 快表tlb 简
- 下一篇: 【转】3.4SharePoint服务器端