日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java容器类1:Collection,List,ArrayList,LinkedList深入解读

發(fā)布時(shí)間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java容器类1:Collection,List,ArrayList,LinkedList深入解读 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、 Iterable 與 Iterator

Iterable 是個(gè)接口,實(shí)現(xiàn)此接口使集合對(duì)象可以通過(guò)迭代器遍歷自身元素.

public interface Iterable<T>

修飾符和返回值方法名描述
Iterator<T>iterator()返回一個(gè)內(nèi)部元素為T類型的迭代器
default voidforEach(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>

修飾符和返回值方法名描述
booleanhasNext()判斷迭代器所指元素是否為最后一個(gè)
Enext()下一個(gè)元素
default Voidremove()移除迭代器指向的當(dāng)前元素
default VoidforEachRemaining(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 } 60

2、Collection

Collection 是容器類的接口,里面可以存放很多Elements,很多容器都實(shí)現(xiàn)了該接口。

public interface Collection<E> extends Iterable<E>

修飾符和返回值方法名描述
intsize()判斷容器的大小
booleanisEmpty()判空
booleancontains(Object o)是否包含某元素
Object[]toArray()轉(zhuǎn)化為數(shù)組
<T> T[]toArray(T[] a)將容器中所有元素拷貝到a中,如果a不夠大,則拷貝到返回的數(shù)組中。(見AbstactCollection中實(shí)現(xiàn))
booleanadd(E e)添加元素
booleanremove(Object o)移除容器中第一個(gè)出現(xiàn)Object對(duì)象,如果Object為null,則移除第一個(gè)出現(xiàn)的null。如果沒有Object對(duì)象返回false
booleancontainsAll(Collection<?> c)包含c中所有元素
booleanaddAll(Collection<? extends E> c);將c中所有元素添加到容器中
booleanremoveAll(Collection<?> c)如果容器中包含c中的元素,刪除。(調(diào)用remove(Object))
default booleanremoveIf(Predicate<? super E> filter)移除所有符合條件的元素(JDK1.8中引入)
booleanretainAll(Collection<?> c)保留在c中出現(xiàn)的元素,其它全部移除
booleanclear() 
booleanequals(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 voidsort(Comparator<? super E> c)將List中所有元素排序
E?get(int index); 
E?set(int index, E element) 
E?remove(int index) 
intindexOf(Object o)o在List中第一次出現(xiàn)的位置
intlastIndexOf(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() 
Enext() 
boolean?hasPrevious() 
Eprevious() 
intnextIndex() 
intpreviousIndex() 
void?remove()刪除next()返回元素
void?set(E e)替換next()返回的元素
void?add(E e)在nextIndex()后插入元素

首先需要明確ListIterator迭代器的作用:

  • 允許我們向前、向后兩個(gè)方向遍歷 List;
  • 在遍歷時(shí)修改 List 的元素;
  • 遍歷時(shí)獲取迭代器當(dāng)前游標(biāo)所在位置。
  • 注意,迭代器 沒有當(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ù)組中?答案見下面這段源碼

    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);? // 將舊數(shù)據(jù)拷貝到新數(shù)組中 11 }

    其它接口不再細(xì)說(shuō)。

    3.4 LinkedList

    ?

    1 public class LinkedList<E> 2 extends

    AbstractSequentialList<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)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。