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