集合List接口詳解【Java提高十六】

?

在編寫java程序中,我們最常用的除了八種基本數(shù)據(jù)類型,String對(duì)象外還有一個(gè)集合類,在我們的的程序中到處充斥著集合類的身影!java中集合大家族的成員實(shí)在是太豐富了,有常用的ArrayList、HashMap、HashSet,也有不常用的Stack、Queue,有線程安全的Vector、HashTable,也有線程不安全的LinkedList、TreeMap等等!

???????上面的圖展示了整個(gè)集合大家族的成員以及他們之間的關(guān)系。下面就上面的各個(gè)接口、基類做一些簡(jiǎn)單的介紹(主要介紹各個(gè)集合的特點(diǎn)。區(qū)別),更加詳細(xì)的介紹會(huì)在不久的將來(lái)一一講解。

一、Collection接口

???????Collection接口是最基本的集合接口,它不提供直接的實(shí)現(xiàn),Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。Collection所代表的是一種規(guī)則,它所包含的元素都必須遵循一條或者多條規(guī)則。如有些允許重復(fù)而有些則不能重復(fù)、有些必須要按照順序插入而有些則是散列,有些支持排序但是有些則不支持。

???????在Java中所有實(shí)現(xiàn)了Collection接口的類都必須提供兩套標(biāo)準(zhǔn)的構(gòu)造函數(shù),一個(gè)是無(wú)參,用于創(chuàng)建一個(gè)空的Collection,一個(gè)是帶有Collection參數(shù)的有參構(gòu)造函數(shù),用于創(chuàng)建一個(gè)新的Collection,這個(gè)新的Collection與傳入進(jìn)來(lái)的Collection具備相同的元素。

二、List接口

???????List接口為Collection直接接口。List所代表的是有序的Collection,即它用某種特定的插入順序來(lái)維護(hù)元素順序。用戶可以對(duì)列表中每個(gè)元素的插入位置進(jìn)行精確地控制,同時(shí)可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問(wèn)元素,并搜索列表中的元素。實(shí)現(xiàn)List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。

2.1、ArrayList

ArrayList是一個(gè)動(dòng)態(tài)數(shù)組,也是我們最常用的集合。它允許任何符合規(guī)則的元素插入甚至包括null。每一個(gè)ArrayList都有一個(gè)初始容量(10),該容量代表了數(shù)組的大小。隨著容器中的元素不斷增加,容器的大小也會(huì)隨著增加。在每次向容器中增加元素的同時(shí)都會(huì)進(jìn)行容量檢查,當(dāng)快溢出時(shí),就會(huì)進(jìn)行擴(kuò)容操作。所以如果我們明確所插入元素的多少,最好指定一個(gè)初始容量值,避免過(guò)多的進(jìn)行擴(kuò)容操作而浪費(fèi)時(shí)間、效率。

???????size、isEmpty、get、set、iterator 和 listIterator 操作都以固定時(shí)間運(yùn)行。add 操作以分?jǐn)偟墓潭〞r(shí)間運(yùn)行,也就是說(shuō),添加 n 個(gè)元素需要 O(n) 時(shí)間(由于要考慮到擴(kuò)容,所以這不只是添加元素會(huì)帶來(lái)分?jǐn)偣潭〞r(shí)間開銷那樣簡(jiǎn)單)。

ArrayList擅長(zhǎng)于隨機(jī)訪問(wèn)。同時(shí)ArrayList是非同步的。

ArrayList詳解:

一、ArrayList概述

????? ArrayList是實(shí)現(xiàn)List接口的動(dòng)態(tài)數(shù)組,所謂動(dòng)態(tài)就是它的大小是可變的。實(shí)現(xiàn)了所有可選列表操作,并允許包括 null 在內(nèi)的所有元素。除了實(shí)現(xiàn) List 接口外,此類還提供一些方法來(lái)操作內(nèi)部用來(lái)存儲(chǔ)列表的數(shù)組的大小。

????? 每個(gè)ArrayList實(shí)例都有一個(gè)容量,該容量是指用來(lái)存儲(chǔ)列表元素的數(shù)組的大小。默認(rèn)初始容量為10。隨著ArrayList中元素的增加,它的容量也會(huì)不斷的自動(dòng)增長(zhǎng)。在每次添加新的元素時(shí),ArrayList都會(huì)檢查是否需要進(jìn)行擴(kuò)容操作,擴(kuò)容操作帶來(lái)數(shù)據(jù)向新數(shù)組的重新拷貝,所以如果我們知道具體業(yè)務(wù)數(shù)據(jù)量,在構(gòu)造ArrayList時(shí)可以給ArrayList指定一個(gè)初始容量,這樣就會(huì)減少擴(kuò)容時(shí)數(shù)據(jù)的拷貝問(wèn)題。當(dāng)然在添加大量元素前,應(yīng)用程序也可以使用ensureCapacity操作來(lái)增加ArrayList實(shí)例的容量,這可以減少遞增式再分配的數(shù)量。

???注意,ArrayList實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問(wèn)一個(gè)ArrayList實(shí)例,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了列表,那么它必須保持外部同步。所以為了保證同步,最好的辦法是在創(chuàng)建時(shí)完成,以防止意外對(duì)列表進(jìn)行不同步的訪問(wèn):

List?list?=?Collections.synchronizedList(new?ArrayList(...));

二、ArrayList源碼分析????

????? ArrayList我們使用的實(shí)在是太多了,非常熟悉,所以在這里將不介紹它的使用方法。ArrayList是實(shí)現(xiàn)List接口的,底層采用數(shù)組實(shí)現(xiàn),所以它的操作基本上都是基于對(duì)數(shù)組的操作。

????? 2.1、底層使用數(shù)組

????? transient??為java關(guān)鍵字,為變量修飾符,如果用transient聲明一個(gè)實(shí)例變量,當(dāng)對(duì)象存儲(chǔ)時(shí),它的值不需要維持。Java的serialization提供了一種持久化對(duì)象實(shí)例的機(jī)制。當(dāng)持久化對(duì)象時(shí),可能有一個(gè)特殊的對(duì)象數(shù)據(jù)成員,我們不想用serialization機(jī)制來(lái)保存它。為了在一個(gè)特定對(duì)象的一個(gè)域上關(guān)閉serialization,可以在這個(gè)域前加上關(guān)鍵字transient。當(dāng)一個(gè)對(duì)象被序列化的時(shí)候,transient型變量的值不包括在序列化的表示中,然而非transient型的變量是被包括進(jìn)去的。

????? 這里Object[] elementData,就是我們的ArrayList容器,下面介紹的基本操作都是基于該elementData變量來(lái)進(jìn)行操作的。

????? 2.2、構(gòu)造函數(shù)

???? ArrayList提供了三個(gè)構(gòu)造函數(shù):

???? ArrayList():默認(rèn)構(gòu)造函數(shù),提供初始容量為10的空列表。

???? ArrayList(int initialCapacity):構(gòu)造一個(gè)具有指定初始容量的空列表。

???? ArrayList(Collection c):構(gòu)造一個(gè)包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。

????? 2.3、新增

????? ArrayList提供了add(E e)、add(int index, E element)、addAll(Collection c)、addAll(int index, Collection c)、set(int index, E element)這個(gè)五個(gè)方法來(lái)實(shí)現(xiàn)ArrayList增加。

add(E e):將指定的元素添加到此列表的尾部。

這里ensureCapacity()方法是對(duì)ArrayList集合進(jìn)行擴(kuò)容操作,elementData(size++) = e,將列表末尾元素指向e。

add(int index, E element):將指定的元素插入此列表中的指定位置。

????? 在這個(gè)方法中最根本的方法就是System.arraycopy()方法,該方法的根本目的就是將index位置空出來(lái)以供新數(shù)據(jù)插入,這里需要進(jìn)行數(shù)組數(shù)據(jù)的右移,這是非常麻煩和耗時(shí)的,所以如果指定的數(shù)據(jù)集合需要進(jìn)行大量插入(中間插入)操作,推薦使用LinkedList。

addAll(Collection c):按照指定 collection 的迭代器所返回的元素順序,將該 collection 中的所有元素添加到此列表的尾部。

這個(gè)方法無(wú)非就是使用System.arraycopy()方法將C集合(先準(zhǔn)換為數(shù)組)里面的數(shù)據(jù)復(fù)制到elementData數(shù)組中。這里就稍微介紹下System.arraycopy(),因?yàn)橄旅孢€將大量用到該方法。該方法的原型為:public static voidarraycopy(Object?src, int srcPos,?Object?dest, int destPos, int length)。它的根本目的就是進(jìn)行數(shù)組元素的復(fù)制。即從指定源數(shù)組中復(fù)制一個(gè)數(shù)組,復(fù)制從指定的位置開始,到目標(biāo)數(shù)組的指定位置結(jié)束。將源數(shù)組src從srcPos位置開始復(fù)制到dest數(shù)組中,復(fù)制長(zhǎng)度為length,數(shù)據(jù)從dest的destPos位置開始粘貼。

addAll(int index, Collection c):從指定的位置開始,將指定 collection 中的所有元素插入到此列表中。

set(int index, E element):用指定的元素替代此列表中指定位置上的元素。

????? 2.4、刪除

??????ArrayList提供了remove(int index)、remove(Object o)、removeRange(int fromIndex, int toIndex)、removeAll()四個(gè)方法進(jìn)行元素的刪除。

remove(int index):移除此列表中指定位置上的元素。

remove(Object o):移除此列表中首次出現(xiàn)的指定元素(如果存在)。

????? 其中fastRemove()方法用于移除指定位置的元素。如下

????? removeRange(int fromIndex, int toIndex):移除列表中索引在fromIndex(包括)和toIndex(不包括)之間的所有元素。

removeAll():是繼承自AbstractCollection的方法,ArrayList本身并沒(méi)有提供實(shí)現(xiàn)。

????? 2.5、查找

????? ArrayList提供了get(int index)用讀取ArrayList中的元素。由于ArrayList是動(dòng)態(tài)數(shù)組,所以我們完全可以根據(jù)下標(biāo)來(lái)獲取ArrayList中的元素,而且速度還比較快,故ArrayList長(zhǎng)于隨機(jī)訪問(wèn)。

???? 2.6、擴(kuò)容

????? 在上面的新增方法的源碼中我們發(fā)現(xiàn)每個(gè)方法中都存在這個(gè)方法:ensureCapacity(),該方法就是ArrayList的擴(kuò)容方法。在前面就提過(guò)ArrayList每次新增元素時(shí)都會(huì)需要進(jìn)行容量檢測(cè)判斷,若新增元素后元素的個(gè)數(shù)會(huì)超過(guò)ArrayList的容量,就會(huì)進(jìn)行擴(kuò)容操作來(lái)滿足新增元素的需求。所以當(dāng)我們清楚知道業(yè)務(wù)數(shù)據(jù)量或者需要插入大量元素前,我可以使用ensureCapacity來(lái)手動(dòng)增加ArrayList實(shí)例的容量,以減少遞增式再分配的數(shù)量。

????? 在這里有一個(gè)疑問(wèn),為什么每次擴(kuò)容處理會(huì)是1.5倍,而不是2.5、3、4倍呢?通過(guò)google查找,發(fā)現(xiàn)1.5倍的擴(kuò)容是最好的倍數(shù)。因?yàn)橐淮涡詳U(kuò)容太大(例如2.5倍)可能會(huì)浪費(fèi)更多的內(nèi)存(1.5倍最多浪費(fèi)33%,而2.5被最多會(huì)浪費(fèi)60%,3.5倍則會(huì)浪費(fèi)71%……)。但是一次性擴(kuò)容太小,需要多次對(duì)數(shù)組重新分配內(nèi)存,對(duì)性能消耗比較嚴(yán)重。所以1.5倍剛剛好,既能滿足性能需求,也不會(huì)造成很大的內(nèi)存消耗。

????? 處理這個(gè)ensureCapacity()這個(gè)擴(kuò)容數(shù)組外,ArrayList還給我們提供了將底層數(shù)組的容量調(diào)整為當(dāng)前列表保存的實(shí)際元素的大小的功能。它可以通過(guò)trimToSize()方法來(lái)實(shí)現(xiàn)。該方法可以最小化ArrayList實(shí)例的存儲(chǔ)量。

2.2、LinkedList

???????同樣實(shí)現(xiàn)List接口的LinkedList與ArrayList不同,ArrayList是一個(gè)動(dòng)態(tài)數(shù)組,而LinkedList是一個(gè)雙向鏈表。所以它除了有ArrayList的基本操作方法外還額外提供了get,remove,insert方法在LinkedList的首部或尾部。

???????由于實(shí)現(xiàn)的方式不同,LinkedList不能隨機(jī)訪問(wèn),它所有的操作都是要按照雙重鏈表的需要執(zhí)行。在列表中索引的操作將從開頭或結(jié)尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過(guò)較低的代價(jià)在List中進(jìn)行插入和刪除操作。

與ArrayList一樣,LinkedList也是非同步的。如果多個(gè)線程同時(shí)訪問(wèn)一個(gè)List,則必須自己實(shí)現(xiàn)訪問(wèn)同步。一種解決方法是在創(chuàng)建List時(shí)構(gòu)造一個(gè)同步的List:

List list = Collections.synchronizedList(new LinkedList(...));

LinkedList詳解:

一、概述

?????? LinkedList與ArrayList一樣實(shí)現(xiàn)List接口,只是ArrayList是List接口的大小可變數(shù)組的實(shí)現(xiàn),LinkedList是List接口鏈表的實(shí)現(xiàn)。基于鏈表實(shí)現(xiàn)的方式使得LinkedList在插入和刪除時(shí)更優(yōu)于ArrayList,而隨機(jī)訪問(wèn)則比ArrayList遜色些。

???????LinkedList實(shí)現(xiàn)所有可選的列表操作,并允許所有的元素包括null。

除了實(shí)現(xiàn) List 接口外,LinkedList 類還為在列表的開頭及結(jié)尾 get、remove 和 insert 元素提供了統(tǒng)一的命名方法。這些操作允許將鏈接列表用作堆棧、隊(duì)列或雙端隊(duì)列。

???????此類實(shí)現(xiàn) Deque 接口,為 add、poll 提供先進(jìn)先出隊(duì)列操作,以及其他堆棧和雙端隊(duì)列操作。

???????所有操作都是按照雙重鏈接列表的需要執(zhí)行的。在列表中編索引的操作將從開頭或結(jié)尾遍歷列表(從靠近指定索引的一端)。

同時(shí),與ArrayList一樣此實(shí)現(xiàn)不是同步的。

(以上摘自JDK 6.0 API)。

二、源碼分析

2.1、定義

? ? ? ?首先我們先看LinkedList的定義:

從這段代碼中我們可以清晰地看出LinkedList繼承AbstractSequentialList,實(shí)現(xiàn)List、Deque、Cloneable、Serializable。其中AbstractSequentialList提供了 List 接口的骨干實(shí)現(xiàn),從而最大限度地減少了實(shí)現(xiàn)受“連續(xù)訪問(wèn)”數(shù)據(jù)存儲(chǔ)(如鏈接列表)支持的此接口所需的工作,從而以減少實(shí)現(xiàn)List接口的復(fù)雜度。Deque一個(gè)線性 collection,支持在兩端插入和移除元素,定義了雙端隊(duì)列的操作。

2.2、屬性

???????在LinkedList中提供了兩個(gè)基本屬性size、header。

???????其中size表示的LinkedList的大小,header表示鏈表的表頭,Entry為節(jié)點(diǎn)對(duì)象。

???????上面為Entry對(duì)象的源代碼,Entry為L(zhǎng)inkedList的內(nèi)部類,它定義了存儲(chǔ)的元素。該元素的前一個(gè)元素、后一個(gè)元素,這是典型的雙向鏈表定義方式。

2.3、構(gòu)造方法

???????LinkedList提高了兩個(gè)構(gòu)造方法:LinkedLis()和LinkedList(Collection c)。

???????LinkedList()構(gòu)造一個(gè)空列表。里面沒(méi)有任何元素,僅僅只是將header節(jié)點(diǎn)的前一個(gè)元素、后一個(gè)元素都指向自身。

???????LinkedList(Collection c): 構(gòu)造一個(gè)包含指定 collection 中的元素的列表,這些元素按其 collection 的迭代器返回的順序排列。該構(gòu)造函數(shù)首先會(huì)調(diào)用LinkedList(),構(gòu)造一個(gè)空列表,然后調(diào)用了addAll()方法將Collection中的所有元素添加到列表中。以下是addAll()的源代碼:

???????在addAll()方法中,涉及到了兩個(gè)方法,一個(gè)是entry(int index),該方法為L(zhǎng)inkedList的私有方法,主要是用來(lái)查找index位置的節(jié)點(diǎn)元素。

???????從該方法有兩個(gè)遍歷方向中我們也可以看出LinkedList是雙向鏈表,這也是在構(gòu)造方法中為什么需要將header的前、后節(jié)點(diǎn)均指向自己。

???????如果對(duì)數(shù)據(jù)結(jié)構(gòu)有點(diǎn)了解,對(duì)上面所涉及的內(nèi)容應(yīng)該問(wèn)題,我們只需要清楚一點(diǎn):LinkedList是雙向鏈表,其余都迎刃而解。

由于篇幅有限,下面將就LinkedList中幾個(gè)常用的方法進(jìn)行源碼分析。

2.4、增加方法

???????add(E e): 將指定元素添加到此列表的結(jié)尾。

該方法調(diào)用addBefore方法,然后直接返回true,對(duì)于addBefore()而已,它為L(zhǎng)inkedList的私有方法。

???????在addBefore方法中無(wú)非就是做了這件事:構(gòu)建一個(gè)新節(jié)點(diǎn)newEntry,然后修改其前后的引用。

???????LinkedList還提供了其他的增加方法:

add(int index, E element):在此列表中指定的位置插入指定的元素。

addAll(Collection c):添加指定 collection 中的所有元素到此列表的結(jié)尾,順序是指定 collection 的迭代器返回這些元素的順序。

addAll(int index, Collection c):將指定 collection 中的所有元素從指定位置開始插入此列表。

AddFirst(E e): 將指定元素插入此列表的開頭。

addLast(E e): 將指定元素添加到此列表的結(jié)尾。

2.5、移除方法

???????remove(Object o):從此列表中移除首次出現(xiàn)的指定元素(如果存在)。該方法的源代碼如下:

???????該方法首先會(huì)判斷移除的元素是否為null,然后迭代這個(gè)鏈表找到該元素節(jié)點(diǎn),最后調(diào)用remove(Entry e),remove(Entry e)為私有方法,是LinkedList中所有移除方法的基礎(chǔ)方法,如下:

???????其他的移除方法:

clear(): 從此列表中移除所有元素。

remove():獲取并移除此列表的頭(第一個(gè)元素)。

remove(int index):移除此列表中指定位置處的元素。

remove(Objec o):從此列表中移除首次出現(xiàn)的指定元素(如果存在)。

removeFirst():移除并返回此列表的第一個(gè)元素。

removeFirstOccurrence(Object o):從此列表中移除第一次出現(xiàn)的指定元素(從頭部到尾部遍歷列表時(shí))。

removeLast():移除并返回此列表的最后一個(gè)元素。

removeLastOccurrence(Object o):從此列表中移除最后一次出現(xiàn)的指定元素(從頭部到尾部遍歷列表時(shí))。

2.5、查找方法

???????對(duì)于查找方法的源碼就沒(méi)有什么好介紹了,無(wú)非就是迭代,比對(duì),然后就是返回當(dāng)前值。

get(int index):返回此列表中指定位置處的元素。

getFirst():返回此列表的第一個(gè)元素。

getLast():返回此列表的最后一個(gè)元素。

indexOf(Object o):返回此列表中首次出現(xiàn)的指定元素的索引,如果此列表中不包含該元素,則返回 -1。

lastIndexOf(Object o):返回此列表中最后出現(xiàn)的指定元素的索引,如果此列表中不包含該元素,則返回 -1。

2.3、Vector

???????與ArrayList相似,但是Vector是同步的。所以說(shuō)Vector是線程安全的動(dòng)態(tài)數(shù)組。它的操作與ArrayList幾乎一樣。

Vector詳解

一、Vector簡(jiǎn)介

??????? Vector可以實(shí)現(xiàn)可增長(zhǎng)的對(duì)象數(shù)組。與數(shù)組一樣,它包含可以使用整數(shù)索引進(jìn)行訪問(wèn)的組件。不過(guò),Vector的大小是可以增加或者減小的,以便適應(yīng)創(chuàng)建Vector后進(jìn)行添加或者刪除操作。

????????Vector實(shí)現(xiàn)List接口,繼承AbstractList類,所以我們可以將其看做隊(duì)列,支持相關(guān)的添加、刪除、修改、遍歷等功能。

????????Vector實(shí)現(xiàn)RandmoAccess接口,即提供了隨機(jī)訪問(wèn)功能,提供提供快速訪問(wèn)功能。在Vector我們可以直接訪問(wèn)元素。

????????Vector 實(shí)現(xiàn)了Cloneable接口,支持clone()方法,可以被克隆。

????????Vector提供了四個(gè)構(gòu)造函數(shù):

????????在成員變量方面,Vector提供了elementData , elementCount, capacityIncrement三個(gè)成員變量。其中

????????elementData :"Object[]類型的數(shù)組",它保存了Vector中的元素。按照Vector的設(shè)計(jì)elementData為一個(gè)動(dòng)態(tài)數(shù)組,可以隨著元素的增加而動(dòng)態(tài)的增長(zhǎng),其具體的增加方式后面提到(ensureCapacity方法)。如果在初始化Vector時(shí)沒(méi)有指定容器大小,則使用默認(rèn)大小為10.

elementCount:Vector對(duì)象中的有效組件數(shù)。

????????capacityIncrement:向量的大小大于其容量時(shí),容量自動(dòng)增加的量。如果在創(chuàng)建Vector時(shí),指定了capacityIncrement的大小;則,每次當(dāng)Vector中動(dòng)態(tài)數(shù)組容量增加時(shí)>,增加的大小都是capacityIncrement。如果容量的增量小于等于零,則每次需要增大容量時(shí),向量的容量將增大一倍。

????????同時(shí)Vector是線程安全的!

二、源碼解析

????????對(duì)于源碼的解析,LZ在這里只就增加(add)刪除(remove)兩個(gè)方法進(jìn)行講解。

2.1增加:add(E e)

????????add(E e):將指定元素添加到此向量的末尾。??

????????這個(gè)方法相對(duì)而言比較簡(jiǎn)單,具體過(guò)程就是先確認(rèn)容器的大小,看是否需要進(jìn)行擴(kuò)容操作,然后將E元素添加到此向量的末尾。

????????對(duì)于Vector整個(gè)的擴(kuò)容過(guò)程,就是根據(jù)capacityIncrement確認(rèn)擴(kuò)容大小的,若capacityIncrement <= 0 則擴(kuò)大一倍,否則擴(kuò)大至capacityIncrement 。當(dāng)然這個(gè)容量的最大范圍為Integer.MAX_VALUE即,2^32 - 1,所以Vector并不是可以無(wú)限擴(kuò)充的。

2.2、remove(Object o)

????????因?yàn)閂ector底層是使用數(shù)組實(shí)現(xiàn)的,所以它的操作都是對(duì)數(shù)組進(jìn)行操作,只不過(guò)其是可以隨著元素的增加而動(dòng)態(tài)的改變?nèi)萘看笮。鋵?shí)現(xiàn)方法是是使用Arrays.copyOf方法將舊數(shù)據(jù)拷貝到一個(gè)新的大容量數(shù)組中。Vector的整個(gè)內(nèi)部實(shí)現(xiàn)都比較簡(jiǎn)單,這里就不在重述了。

三、Vector遍歷

????????Vector支持4種遍歷方式。

3.1、隨機(jī)訪問(wèn)

????????因?yàn)閂ector實(shí)現(xiàn)了RandmoAccess接口,可以通過(guò)下標(biāo)來(lái)進(jìn)行隨機(jī)訪問(wèn)。

3.2、迭代器

3.3、for循環(huán)

3.4、Enumeration循環(huán)

2.4、Stack

???????Stack繼承自Vector,實(shí)現(xiàn)一個(gè)后進(jìn)先出的堆棧。Stack提供5個(gè)額外的方法使得Vector得以被當(dāng)作堆棧使用。基本的push和pop 方法,還有peek方法得到棧頂?shù)脑兀琫mpty方法測(cè)試堆棧是否為空,search方法檢測(cè)一個(gè)元素在堆棧中的位置。Stack剛創(chuàng)建后是空棧。

Stack詳解:

在Java中Stack類表示后進(jìn)先出(LIFO)的對(duì)象堆棧。棧是一種非常常見的數(shù)據(jù)結(jié)構(gòu),它采用典型的先進(jìn)后出的操作方式完成的。每一個(gè)棧都包含一個(gè)棧頂,每次出棧是將棧頂?shù)臄?shù)據(jù)取出,如下:

????????Stack通過(guò)五個(gè)操作對(duì)Vector進(jìn)行擴(kuò)展,允許將向量視為堆棧。這個(gè)五個(gè)操作如下:

????????Stack繼承Vector,他對(duì)Vector進(jìn)行了簡(jiǎn)單的擴(kuò)展:

view plai

????????Stack的實(shí)現(xiàn)非常簡(jiǎn)單,僅有一個(gè)構(gòu)造方法,五個(gè)實(shí)現(xiàn)方法(從Vector繼承而來(lái)的方法不算與其中),同時(shí)其實(shí)現(xiàn)的源碼非常簡(jiǎn)單

????????Stack的源碼很多都是基于Vector

List總結(jié)

一、List接口概述

List接口,成為有序的Collection也就是序列。該接口可以對(duì)列表中的每一個(gè)元素的插入位置進(jìn)行精確的控制,同時(shí)用戶可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問(wèn)元素,并搜索列表中的元素。 下圖是List接口的框架圖:

????????通過(guò)上面的框架圖,可以對(duì)List的結(jié)構(gòu)了然于心,其各個(gè)類、接口如下:

????????Collection:Collection 層次結(jié)構(gòu) 中的根接口。它表示一組對(duì)象,這些對(duì)象也稱為 collection 的元素。對(duì)于Collection而言,它不提供任何直接的實(shí)現(xiàn),所有的實(shí)現(xiàn)全部由它的子類負(fù)責(zé)。

????????AbstractCollection:提供 Collection 接口的骨干實(shí)現(xiàn),以最大限度地減少了實(shí)現(xiàn)此接口所需的工作。對(duì)于我們而言要實(shí)現(xiàn)一個(gè)不可修改的 collection,只需擴(kuò)展此類,并提供 iterator 和 size 方法的實(shí)現(xiàn)。但要實(shí)現(xiàn)可修改的 collection,就必須另外重寫此類的 add 方法(否則,會(huì)拋出 UnsupportedOperationException),iterator 方法返回的迭代器還必須另外實(shí)現(xiàn)其 remove 方法。

? ? ? ? Iterator:迭代器。

????????ListIterator:系列表迭代器,允許程序員按任一方向遍歷列表、迭代期間修改列表,并獲得迭代器在列表中的當(dāng)前位置。

????????List:繼承于Collection的接口。它代表著有序的隊(duì)列。

????????AbstractList:List 接口的骨干實(shí)現(xiàn),以最大限度地減少實(shí)現(xiàn)“隨機(jī)訪問(wèn)”數(shù)據(jù)存儲(chǔ)(如數(shù)組)支持的該接口所需的工作。

????????Queue:隊(duì)列。提供隊(duì)列基本的插入、獲取、檢查操作。

????????Deque:一個(gè)線性 collection,支持在兩端插入和移除元素。大多數(shù) Deque 實(shí)現(xiàn)對(duì)于它們能夠包含的元素?cái)?shù)沒(méi)有固定限制,但此接口既支持有容量限制的雙端隊(duì)列,也支持沒(méi)有固定大小限制的雙端隊(duì)列。

????????AbstractSequentialList:提供了 List 接口的骨干實(shí)現(xiàn),從而最大限度地減少了實(shí)現(xiàn)受“連續(xù)訪問(wèn)”數(shù)據(jù)存儲(chǔ)(如鏈接列表)支持的此接口所需的工作。從某種意義上說(shuō),此類與在列表的列表迭代器上實(shí)現(xiàn)“隨機(jī)訪問(wèn)”方法。

????????LinkedList:List 接口的鏈接列表實(shí)現(xiàn)。它實(shí)現(xiàn)所有可選的列表操作。

????????ArrayList:List 接口的大小可變數(shù)組的實(shí)現(xiàn)。它實(shí)現(xiàn)了所有可選列表操作,并允許包括 null 在內(nèi)的所有元素。除了實(shí)現(xiàn) List 接口外,此類還提供一些方法來(lái)操作內(nèi)部用來(lái)存儲(chǔ)列表的數(shù)組的大小。

????????Vector:實(shí)現(xiàn)可增長(zhǎng)的對(duì)象數(shù)組。與數(shù)組一樣,它包含可以使用整數(shù)索引進(jìn)行訪問(wèn)的組件。

????????Stack:后進(jìn)先出(LIFO)的對(duì)象堆棧。它通過(guò)五個(gè)操作對(duì)類 Vector 進(jìn)行了擴(kuò)展 ,允許將向量視為堆棧。

????????Enumeration:枚舉,實(shí)現(xiàn)了該接口的對(duì)象,它生成一系列元素,一次生成一個(gè)。連續(xù)調(diào)用 nextElement 方法將返回一系列的連續(xù)元素。

二、使用場(chǎng)景

????????學(xué)習(xí)知識(shí)的根本目的就是使用它。每個(gè)知識(shí)點(diǎn)都有它的使用范圍。集合也是如此,在Java中集合的家族非常龐大,每個(gè)成員都有最適合的使用場(chǎng)景。在剛剛接觸List時(shí),LZ就說(shuō)過(guò)如果涉及到“棧”、“隊(duì)列”、“鏈表”等操作,請(qǐng)優(yōu)先考慮用List。至于是那個(gè)List則分如下:

????????1、對(duì)于需要快速插入、刪除元素,則需使用LinkedList。

????????2、對(duì)于需要快速訪問(wèn)元素,則需使用ArrayList。

????????3、對(duì)于“單線程環(huán)境”或者“多線程環(huán)境,但是List僅被一個(gè)線程操作”,需要考慮使用非同步的類,如果是“多線程環(huán)境,切List可能同時(shí)被多個(gè)線程操作”,考慮使用同步的類(如Vector)。

2.1ArrayList、LinkedList性能分析

????????在List中我們使用最普遍的就是LinkedList和ArrayList,同時(shí)我們也了解了他們兩者之間的使用場(chǎng)景和區(qū)別。

????????運(yùn)行結(jié)果:

????????從上面的運(yùn)行結(jié)果我們可以清晰的看出ArrayList、LinkedList、Vector增加、刪除、遍歷的效率問(wèn)題。下面我就插入方法add(int index, E element),delete、get方法各位如有興趣可以研究研究。

????????首先我們先看三者之間的源碼:

????????ArrayList

????????rangeCheckForAdd、ensureCapacityInternal兩個(gè)方法沒(méi)有什么影響,真正產(chǎn)生影響的是System.arraycopy方法,該方法是個(gè)JNI函數(shù),是在JVM中實(shí)現(xiàn)的。聲明如下:

???????事實(shí)上我們只需要了解該方法會(huì)移動(dòng)index后面的所有元素即可,這就意味著ArrayList的add(int index, E element)方法會(huì)引起index位置之后所有元素的改變,這真是牽一處而動(dòng)全身。

LinkedList

????????該方法比較簡(jiǎn)單,插入位置在末尾則調(diào)用linkLast方法,否則調(diào)用linkBefore方法,其實(shí)linkLast、linkBefore都是非常簡(jiǎn)單的實(shí)現(xiàn),就是在index位置插入元素,至于index具體為知?jiǎng)t有node方法來(lái)解決,同時(shí)node對(duì)index位置檢索還有一個(gè)加速作用,如下:

????????所以linkedList的插入動(dòng)作比ArrayList動(dòng)作快就在于兩個(gè)方面。

1:linkedList不需要執(zhí)行元素拷貝動(dòng)作,沒(méi)有牽一發(fā)而動(dòng)全身的大動(dòng)作。

2:查找插入位置有加速動(dòng)作即:若index < 雙向鏈表長(zhǎng)度的1/2,則從前向后查找; 否則,從后向前查找。

????????Vector

????????Vector的實(shí)現(xiàn)機(jī)制和ArrayList一樣,同樣是使用動(dòng)態(tài)數(shù)組來(lái)實(shí)現(xiàn)的,所以他們兩者之間的效率差不多,add的源碼也一樣,如下:

????????上面是針對(duì)ArrayList、LinkedList、Vector三者之間的add(int index,E element)方法的解釋,解釋了LinkedList的插入動(dòng)作要比ArrayList、Vector的插入動(dòng)作效率為什么要高出這么多!至于delete、get兩個(gè)方法LZ就不多解釋了。

2.2、Vector和ArrayList的區(qū)別

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評(píng)論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,354評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,554評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容