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