摘要:接口的實(shí)現(xiàn)類表示有序的集合元素可以重復(fù),根據(jù)索引來(lái)尋找元素,放入其中的元素的存儲(chǔ)順序和放入順序是一致的。包下的集合并發(fā)類與等方法裝飾的類有什么不同先講一下這個(gè)線程安全的類。
List接口的實(shí)現(xiàn)類
List表示有序的集合(元素可以重復(fù)),根據(jù)索引來(lái)尋找元素,放入其中的元素的存儲(chǔ)順序和放入順序是一致的。
ArrayList0.繼承自AbstractList,擁有通用的方法如Iterator迭代器。實(shí)現(xiàn)了List接口。
1.底層是transient Object[] elementData 數(shù)組??梢钥吹?strong>默認(rèn)大小是10。
2.不同的初始化方式,有一點(diǎn)區(qū)別。
// 未指定,默認(rèn)是10。構(gòu)造的數(shù)組大小為0,要等到放入第一個(gè)元素時(shí)才會(huì)擴(kuò)容成10個(gè)。 Listlist1 = new ArrayList<>(); // 構(gòu)造的數(shù)組大小為0。 List list2 = new ArrayList<>(0); // 構(gòu)造的數(shù)組大小為14 List list3 = new ArrayList<>(14);
3.數(shù)組擴(kuò)容
默認(rèn)初始化的內(nèi)部數(shù)組大小是10,當(dāng)放入第11個(gè)元素時(shí)會(huì)進(jìn)行第一次擴(kuò)容:newCapacity = oldCapacity + oldCapacity >> 1 ,也就是變成原來(lái)的1.5倍。(所以默認(rèn)情況下,放入第11個(gè)元素時(shí),擴(kuò)容成15個(gè);放入第16個(gè)元素時(shí),擴(kuò)容成22個(gè);放入第23個(gè)元素時(shí),擴(kuò)容成33個(gè)。)
數(shù)組擴(kuò)容的操作是進(jìn)行數(shù)組的復(fù)制,所以擴(kuò)容消耗資源,應(yīng)該盡量先指明所需的容量,來(lái)減少擴(kuò)容操作。對(duì)于已經(jīng)存在的ArrayList,在放入大量元素前,可以手動(dòng)進(jìn)行擴(kuò)容:ensureCapacity(capacity) 方法來(lái)重新設(shè)置內(nèi)部數(shù)組的大小。
4.有一個(gè)騷操作,把ArrayList轉(zhuǎn)化成對(duì)象數(shù)組:
// 調(diào)用toArray方法,傳入對(duì)象數(shù)組接收,返回Object[]數(shù)組 Object[] objects2 = appleList.toArray(new Apple[0]); // 類型轉(zhuǎn)換 Apple[] apples3 = (Apple[]) objects2;
5.ArrayList的add(int index, Object obj)和remove(int index) / remove(Object obj),即隨機(jī)的增加、刪除操作都會(huì)進(jìn)行內(nèi)部數(shù)組的復(fù)制,所以ArrayList只適合順序插入、刪除,隨機(jī)訪問get(int index),不適合隨機(jī)增加、刪除操作多的場(chǎng)景。
ArrayList總結(jié)1.初始化時(shí)應(yīng)該指明容量,避免多次的擴(kuò)容操作。如果已經(jīng)分配了容量但是不夠用,建議先手動(dòng)擴(kuò)容大小后再添加元素。
2.使用場(chǎng)景應(yīng)該是隨機(jī)查找比較多而隨機(jī)增加、刪除操作比較少的場(chǎng)景。
LinkedList1.繼承自AbstractSequentialList,擁有通用的方法如iterator。實(shí)現(xiàn)List接口。實(shí)現(xiàn)Queue接口,擁有隊(duì)列的特性;實(shí)現(xiàn)Deque接口,擁有雙端隊(duì)列的特性。
2.LinkedList內(nèi)部的節(jié)點(diǎn)。擁有前后指針,實(shí)現(xiàn)的是雙端隊(duì)列的性質(zhì)。
內(nèi)部的私有屬性,存儲(chǔ)了鏈表的節(jié)點(diǎn)個(gè)數(shù)以及保存了鏈表的頭尾指針。
3.因?yàn)長(zhǎng)inkedList實(shí)現(xiàn)了Queue接口、Deque接口,所以它既能作為隊(duì)列也能作為堆棧來(lái)使用。又因?yàn)閷?shí)現(xiàn)了List接口,所以又是有序的Collection。這意味著它有3種數(shù)據(jù)結(jié)構(gòu)的作用,我們應(yīng)該在正確的場(chǎng)景下正確語(yǔ)義化使用,這表示我們要使用合適的接口來(lái)聲明LinedList。(注意雙端隊(duì)列Deque接口提供了傳統(tǒng)Stack的操作方法聲明,所以它可以作為堆棧Stack使用)
4.對(duì)于LinkedList的隨機(jī)訪問操作,它內(nèi)部有一個(gè)優(yōu)化。如果index<(size/2),就從頭部開始查找;否則從尾部開始查找。
LinkedList總結(jié)1.使用場(chǎng)景應(yīng)該是隨機(jī)增加、刪除操作多的情況,而隨機(jī)訪問操作少的情況。
2.LinkedList有3種數(shù)據(jù)結(jié)構(gòu)的身份,我們應(yīng)該在正確的場(chǎng)景下進(jìn)行正確的接口聲明,并且使用與之對(duì)應(yīng)的語(yǔ)義化方法來(lái)操作LinkedList。我們?cè)谑褂脳tack結(jié)構(gòu)的時(shí)候可以使用LinkedList,在使用隊(duì)列Queue的時(shí)候可以使用LinkedList,在使用有序集合(鏈表)的時(shí)候可以使用LinkedList。
Vectorvector作為古老的集合類,是jdk1.2之后才改為實(shí)現(xiàn)List接口的。它與ArrayList的性質(zhì)很像(2者的繼承圖是一樣的),但是其內(nèi)部方法都使用了synchronized修飾來(lái)保證線程安全,這使得對(duì)Vector的操作在多線程下變成了串行操作。要注意的是,它的實(shí)現(xiàn)是使用synchronized修飾整個(gè)方法,而不是方法內(nèi)部的某段代碼,這使得其鎖的粒度特別大,效率十分低!
Vector已經(jīng)不推薦使用了,單線程下我們建議選用ArrayList,多線程下我們建議選用java.util.concurrent包下的CopyOnWriteArray或使用Collections.synchronizedList(ArrayList list)修飾過的ArrayList。
列舉synchronized修飾的add、get操作:
1.默認(rèn)初始化大小為10,擴(kuò)容操作時(shí),如果構(gòu)造時(shí)指明了增大的容量,則增加;否則默認(rèn)變成原來(lái)的2倍。
StackStack作為Vector的子類,可用于實(shí)現(xiàn)堆棧。但是不建議使用,而是使用Deque接口的實(shí)現(xiàn)類如LinkedList、ArrayList來(lái)替代堆棧結(jié)構(gòu)。
為什么不使用Stack,而推薦使用LinkedList呢?原因還是因?yàn)樗^承自Vector,所以它的棧相關(guān)的操作也是synchronized修飾的!所以單線程下,我們還是推薦使用LinkedList所能實(shí)現(xiàn)的棧結(jié)構(gòu);多線程下則可以考慮java.util.concurrent包下的ConcurrentLinkedDeque所能實(shí)現(xiàn)的并發(fā)棧結(jié)構(gòu)或Collections.synchronizedList(LinkedList list)修飾的LinkedList。
當(dāng)然,我們也可以使用ArrayDeque類!講講List集合對(duì)應(yīng)的并發(fā)類
ArrayList對(duì)應(yīng)的,java.util.concurrent.CopyOnWriteArrayList類和Collections.synchronizedList(ArrayList list)所修飾的類。
LinkedList對(duì)應(yīng)的,就是Collections.synchronizedList(LinkedList list)所修飾的類。
要注意的是,到了并發(fā)集合(java.util.concurrent包)這一塊,都是按照接口性質(zhì)設(shè)置的并發(fā)類。所以應(yīng)該講成List接口對(duì)應(yīng)的并發(fā)類是java.util.concurrent.CopyOnWriteArrayList類。
java.util.concurrent包下的集合并發(fā)類與Collections.synchronizedList()等方法裝飾的類有什么不同?先講一下Vector這個(gè)線程安全的List類。其線程安全的實(shí)現(xiàn)方式是對(duì)所有操作都加上了synchronized關(guān)鍵字,其鎖的粒度是整個(gè)方法,這種方式嚴(yán)重影響效率,使得程序串行進(jìn)行。
而Collections.synchronizedList等方法,是采用了裝飾器的模式來(lái)返回一個(gè)包裝類。以Collections.synchronizedList(ArrayList list)為例,返回的包裝類的部分操作如add、get、remove方法是在方法內(nèi)部的代碼塊加上了synchronized關(guān)鍵字,這使得鎖的粒度較?。?p>
而java.util.concurrent包下的CopyOnWriteArrayList,其寫操作是寫時(shí)復(fù)制(就和名字一樣),通過可重入鎖顯式加鎖來(lái)達(dá)到同步互斥的目的。而且每次新加入元素,都復(fù)制原數(shù)組一份,然后對(duì)新數(shù)組進(jìn)行增加操作,然后在替換原引用,這就達(dá)到了寫入分離。(刪除操作同樣的道理)這里很重要,下面要講一下get方法!
get方法沒有任何加鎖同步操作!這里就很有趣了!根據(jù)對(duì)寫入操作的分析,如果并發(fā)時(shí)一個(gè)線程在寫入,另外一個(gè)線程在讀取,那么寫入未完成之前,讀取操作所讀到的數(shù)組是原先的數(shù)組!
所以,這正是CopyOnWrite容器的缺點(diǎn):CopyOnWrite只能保證數(shù)據(jù)最終的一致性,不能保證數(shù)據(jù)的實(shí)時(shí)一致性。并發(fā)情況下,某個(gè)線程讀取到的數(shù)據(jù)可能是舊數(shù)據(jù)!
其次,對(duì)內(nèi)存有消耗,如果多個(gè)線程并發(fā)執(zhí)行,那么數(shù)組復(fù)制時(shí)需要新數(shù)組來(lái)保存,就占用了2份內(nèi)存!如果數(shù)組占用的內(nèi)存較大,就會(huì)引發(fā)頻繁的垃圾回收行為,降低性能。
所以對(duì)于CopyOnWrite容器來(lái)說,它適合讀操作頻繁,而寫操作少的并發(fā)場(chǎng)景,比如說數(shù)據(jù)的緩存!
List集合圖下面對(duì)Collection集合下的List有序集合進(jìn)行一個(gè)類圖的整合:
可以看到的是ArrayList和Vector的繼承圖是一致的!它們的區(qū)別就是內(nèi)部實(shí)現(xiàn)不同,所以我們可以大膽地放棄Vector類了。而LinkedList較之于ArrayList,多實(shí)現(xiàn)了Deque接口,這使得它不僅具備了List的特性,還擁有雙端隊(duì)列的特性,可以拿來(lái)做棧、隊(duì)列等結(jié)構(gòu)!
Collection接口繼承自Iterable,這意味著所有的集合類都可以返回迭代器進(jìn)行遍歷。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77271.html
摘要:第三階段常見對(duì)象的學(xué)習(xí)集合框架接口按照集合框架的繼承體系,我們先從中的接口開始學(xué)習(xí)一概述及功能演示概述在中充當(dāng)著一個(gè)什么樣的身份呢有序的也稱為序列實(shí)現(xiàn)這個(gè)接口的用戶以對(duì)列表中每個(gè)元素的插入位置進(jìn)行精確地控制。線程不安全,效率高。 第三階段 JAVA常見對(duì)象的學(xué)習(xí) 集合框架——List接口 showImg(https://segmentfault.com/img/remote/14600...
摘要:集合的長(zhǎng)度的是可變的,可以根據(jù)元素的增加而增長(zhǎng)。如果元素個(gè)數(shù)不是固定的推薦用集合。線程安全,效率低。相對(duì)查詢慢線程安全的相對(duì)增刪慢數(shù)組結(jié)構(gòu)底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快。線程不安全,效率高。 1_對(duì)象數(shù)組的概述和使用 A:案例演示 需求:我有5個(gè)學(xué)生,請(qǐng)把這個(gè)5個(gè)學(xué)生的信息存儲(chǔ)到數(shù)組中,并遍歷數(shù)組,獲取得到每一個(gè)學(xué)生信息。 import net.allidea.bean.Stu...
摘要:提供了一個(gè)操作和等集合的工具類,該工具類提供了大量方法對(duì)集合進(jìn)行排序查詢和修改等操作,還提供了將集合對(duì)象置為不可變對(duì)集合對(duì)象實(shí)現(xiàn)同步控制等方法排序操作反轉(zhuǎn)指定集合中元素的順序?qū)显剡M(jìn)行隨機(jī)排序方法模擬了洗牌動(dòng)作根據(jù)元素的自然順序?qū)χ付? Java提供了一個(gè)操作Set、List和Map等集合的工具類:Collections,該工具類提供了大量方法對(duì)集合進(jìn)行排序、查詢和修改等操作,還提...
摘要:刪除元素后,立即跳出,則正常退出,但不能向后繼續(xù)循環(huán)了刪除后立馬終端循環(huán),會(huì)正常跳出,但代價(jià)是不能繼續(xù)向后循環(huán)了使用迭代器使用迭代器可,正確無(wú)誤的刪除,代碼簡(jiǎn)潔優(yōu)雅,推薦使用使用迭代器可,正確無(wú)誤的刪除注意這里時(shí)而不是 在工作中的許多場(chǎng)景下,我們都會(huì)使用到List這個(gè)數(shù)據(jù)結(jié)構(gòu),那么同樣的有很多場(chǎng)景下需要?jiǎng)h除List中的某一個(gè)元素或某幾個(gè)元素,那么我們?cè)撊绾握_無(wú)誤地刪除List中的元素...
摘要:與在迭代器中的設(shè)計(jì)在中,最典型的與就是關(guān)于迭代器的設(shè)計(jì)。缺點(diǎn)是,迭代器不能正確及時(shí)的反應(yīng)集合中的內(nèi)容,而且一定程度上也增加了內(nèi)存的消耗。 fail-fast與fail-safe簡(jiǎn)介 如果一個(gè)系統(tǒng),當(dāng)有異?;蛘咤e(cuò)誤發(fā)生時(shí)就立即中斷執(zhí)行,這種設(shè)計(jì)稱之為fail-fast。相反如果我們的系統(tǒng)可以在某種異常或者錯(cuò)誤發(fā)生時(shí)繼續(xù)執(zhí)行,不會(huì)被中斷,這種設(shè)計(jì)稱之為fail-safe。 fail-fas...
摘要:并把最終的隨機(jī)數(shù)輸出到控制臺(tái)。方法,在集合中如何存儲(chǔ)元素取決于方法的返回值返回,集合中只有一個(gè)元素。創(chuàng)建集合對(duì)象,傳入比較器。 1_HashSet存儲(chǔ)字符串并遍歷 A:Set集合概述及特點(diǎn) 通過API查看即可 B:案例演示 HashSet存儲(chǔ)字符串并遍歷 import java.util.HashSet; public class Demo1_HashSet { p...
閱讀 893·2021-11-22 15:25
閱讀 1529·2021-09-08 09:45
閱讀 1841·2021-09-02 09:46
閱讀 1430·2019-08-30 15:56
閱讀 1593·2019-08-29 15:14
閱讀 1227·2019-08-29 13:06
閱讀 2069·2019-08-29 12:34
閱讀 1468·2019-08-26 12:14