詳解Java?List中五種常見實現(xiàn)類的使用
一、 List概述
Java中的List
是一個接口,它繼承自Collection
接口,代表了一個有序的集合,其中的元素可以重復(fù)。List提供了一系列方法用于對集合中的元素進(jìn)行操作,例如添加、刪除、獲取元素等。Java中常見的List實現(xiàn)類有ArrayList
、LinkedList
、Vector
、Stack
和CopyOnWriteArrayList
。
在實際開發(fā)中,List接口是一種頻繁使用的數(shù)據(jù)結(jié)構(gòu),它提供了豐富的方法來操作有序的元素集合。由于其靈活性和常用性,List在許多場景下被廣泛應(yīng)用,是開發(fā)人員經(jīng)常選擇的數(shù)據(jù)結(jié)構(gòu)之一。
1.1 List 接口的常見實現(xiàn)類
Java中提供了非常多的使用的List實現(xiàn)類,本文將重點介紹一下這些類以及他們的應(yīng)用場景。首先羅列一下本文要介紹的實現(xiàn)類都有哪些。
1.2 List接口都定義了那些方法
List接口里面定義的方法還是挺多的,大體可以分為六類,下面我將這些方法分類說明一下:
1.添加元素:
- boolean add(E element):向列表的末尾添加一個元素。
- void add(int index, E element):在指定的索引位置添加一個元素。
2.獲取元素:
- E get(int index):獲取指定索引位置的元素。
- int indexOf(Object obj):返回指定元素在列表中首次出現(xiàn)的索引。
- int lastIndexOf(Object obj):返回指定元素在列表中最后出現(xiàn)的索引。
3.刪除元素:
- boolean remove(Object obj):從列表中刪除指定元素的第一個匹配項。
- E remove(int index):刪除指定索引位置的元素。
4.修改元素:
E set(int index, E element):替換指定索引位置的元素。
5.列表大?。?/p>
- int size():返回列表中的元素數(shù)量。
- boolean isEmpty():檢查列表是否為空。
6.遍歷元素:
- 使用迭代器(Iterator)遍歷列表中的元素。
- 使用增強的for循環(huán)(for-each)遍歷列表中的元素。
二、ArrayList
ArrayList
是一個動態(tài)數(shù)組實現(xiàn)的類,它是Java集合框架中List
接口的一個常用實現(xiàn)類。與傳統(tǒng)的數(shù)組相比,ArrayList
具有更靈活的長度和操作方式。
通過使用ArrayList
,可以方便地管理和操作元素集合,它是Java開發(fā)中常用的數(shù)據(jù)結(jié)構(gòu)之一。
2.1 ArrayList的特點
- 動態(tài)數(shù)組:ArrayList在內(nèi)部使用數(shù)組來存儲元素,并且具有動態(tài)擴容的能力。當(dāng)元素數(shù)量超過當(dāng)前數(shù)組容量時,ArrayList會自動增加其容量以容納更多的元素。
- 有序集合:ArrayList是一個有序集合,可以按照元素的插入順序迭代訪問元素。
- 允許重復(fù)元素:ArrayList允許存儲重復(fù)的元素,即可以在列表中存儲相同的元素多次。
- 隨機訪問:由于ArrayList使用基于索引的數(shù)組實現(xiàn),因此可以通過索引進(jìn)行快速的隨機訪問和修改元素??梢允褂胓et(index)方法根據(jù)索引獲取元素,使用set(index, element)方法根據(jù)索引修改元素。
- 動態(tài)修改:ArrayList提供了一系列方法來動態(tài)修改列表,包括添加元素、刪除元素、插入元素等。常用的方法包括add(element)用于在列表末尾添加元素,remove(element)用于刪除指定元素,add(index, element)用于在指定位置插入元素等。
- 支持迭代器:ArrayList實現(xiàn)了Iterable接口,因此可以使用迭代器來遍歷列表中的元素??梢酝ㄟ^iterator()方法獲取迭代器,并使用hasNext()和next()方法依次訪問元素。
- 非線程安全:ArrayList不是線程安全的,如果在多個線程同時修改ArrayList時,需要進(jìn)行外部同步或使用線程安全的替代類,如CopyOnWriteArrayList。
2.2 ArrayList使用案例
demo:
import java.util.ArrayList; import java.util.List; public class ArrayListDemo { public static void main(String[] args) { List<String> fruits = new ArrayList<>(); fruits.add("蘋果"); fruits.add("香蕉"); fruits.add("榴蓮"); fruits.add("菠蘿"); // 獲取ArrayList的大小 int size = fruits.size(); System.out.println("ArrayList的大?。? + size); // 訪問指定位置的元素 String element = fruits.get(2); System.out.println("索引2上的元素:" + element); // 修改指定位置的元素 fruits.set(1, "菠蘿蜜"); System.out.println("修改后的ArrayList:" + fruits); // 刪除指定位置的元素 String removedElement = fruits.remove(3); System.out.println("被刪除的元素:" + removedElement); System.out.println("刪除后的ArrayList:" + fruits); // 檢查ArrayList是否包含某個元素 boolean contains = fruits.contains(30); System.out.println("ArrayList是否包含30:" + contains); // 清空ArrayList fruits.clear(); System.out.println("清空后的ArrayList:" + fruits); } }
輸出結(jié)果:
ArrayList的大?。?
索引2上的元素:榴蓮
修改后的ArrayList:[蘋果, 菠蘿蜜, 榴蓮, 菠蘿]
被刪除的元素:菠蘿
刪除后的ArrayList:[蘋果, 菠蘿蜜, 榴蓮]
ArrayList是否包含30:false
清空后的ArrayList:[]
三、LinkedList
LinkedList
是Java集合框架中的一個實現(xiàn)類,它實現(xiàn)了List
接口和Deque
接口,基于雙向鏈表的數(shù)據(jù)結(jié)構(gòu)。相比于ArrayList
,LinkedList
在某些場景下具有一些特殊的優(yōu)勢和適用性。
LinkedList
適用于需要頻繁進(jìn)行插入和刪除操作的場景,特別是在實現(xiàn)隊列和棧時。
3.1 LinkedList的特點
- 雙向鏈表:LinkedList內(nèi)部使用雙向鏈表來存儲元素。每個節(jié)點都包含對前一個節(jié)點和后一個節(jié)點的引用,因此在插入和刪除元素時,LinkedList比ArrayList更高效。由于不需要像ArrayList那樣進(jìn)行數(shù)組的擴容和元素的移動,LinkedList對于頻繁的插入和刪除操作更快。
- 高效的插入和刪除操作:由于LinkedList的雙向鏈表結(jié)構(gòu),插入和刪除元素的平均時間復(fù)雜度為O(1),而在ArrayList中,這些操作的時間復(fù)雜度為O(n),其中n是元素的數(shù)量。因此,在需要頻繁進(jìn)行插入和刪除操作的場景下,LinkedList通常比ArrayList更適合。
- 低效的隨機訪問:由于LinkedList是基于鏈表實現(xiàn)的,訪問元素需要從頭節(jié)點或尾節(jié)點開始遍歷鏈表,因此隨機訪問元素的效率較低。在需要頻繁進(jìn)行隨機訪問的場景下,ArrayList通常更適合。
- 適合實現(xiàn)隊列和棧:LinkedList實現(xiàn)了Queue接口和Deque接口,因此可以用作隊列(先進(jìn)先出)和棧(后進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu)。它提供了相關(guān)的方法,如add()和remove()用于隊列操作,以及push()和pop()用于棧操作。
- 內(nèi)存消耗較大:相比于ArrayList,LinkedList在存儲相同數(shù)量元素時需要更多的內(nèi)存,因為每個節(jié)點都需要額外的引用來指向前一個節(jié)點和后一個節(jié)點。
3.2 LinkedList使用案例
demo:
import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { // 創(chuàng)建一個LinkedList,用于存儲字符串 LinkedList<String> names = new LinkedList<>(); // 添加元素到LinkedList names.add("張三"); names.add("李四"); names.add("王五"); names.add("趙六"); // 獲取LinkedList的大小 int size = names.size(); System.out.println("LinkedList的大?。? + size); // 訪問指定位置的元素 String element = names.get(2); System.out.println("索引2上的元素:" + element); // 修改指定位置的元素 names.set(1, "林七"); System.out.println("修改后的LinkedList:" + names); // 刪除指定位置的元素 String removedElement = names.remove(3); System.out.println("被刪除的元素:" + removedElement); System.out.println("刪除后的LinkedList:" + names); // 在特定位置插入元素 names.add(0, "馬八"); System.out.println("插入后的LinkedList:" + names); // 檢查LinkedList是否包含某個元素 boolean contains = names.contains("李四"); System.out.println("LinkedList是否包含李四:" + contains); // 清空LinkedList names.clear(); System.out.println("清空后的LinkedList:" + names); } }
輸出結(jié)果:
LinkedList的大?。?
索引2上的元素:王五
修改后的LinkedList:[張三, 林七, 王五, 趙六]
被刪除的元素:趙六
刪除后的LinkedList:[張三, 林七, 王五]
插入后的LinkedList:[馬八, 張三, 林七, 王五]
LinkedList是否包含李四:false
清空后的LinkedList:[]
四、Vector
Vector
是Java集合框架中的一個類,它實現(xiàn)了List接口,是一個動態(tài)數(shù)組(類似于ArrayList
)的線程安全版本。與ArrayList
相比,Vector
具有額外的同步機制,可以在多線程環(huán)境中安全地使用。
雖然Vector
具有線程安全的特性,但由于同步機制的開銷,它在性能上可能不如ArrayList
。因此,如果在單線程環(huán)境下工作,建議使用ArrayList
;僅在多線程環(huán)境下需要線程安全操作時,才考慮使用Vector
。
需要注意的是,在Java 5及以后的版本中,推薦使用更加高效的并發(fā)集合類,如CopyOnWriteArrayList
或ConcurrentLinkedDeque
,來替代Vector
,因為它們提供更好的性能和擴展性。
4.1 Vector 的特點
- 動態(tài)數(shù)組:Vector內(nèi)部使用數(shù)組來存儲元素,并且具有動態(tài)擴容的能力。當(dāng)元素數(shù)量超過當(dāng)前數(shù)組容量時,Vector會自動增加其容量以容納更多的元素。
- 線程安全:Vector的操作是線程安全的,即多個線程可以同時對Vector進(jìn)行操作而不會導(dǎo)致數(shù)據(jù)不一致或其他線程安全問題。Vector通過使用同步機制來實現(xiàn)線程安全,確保在多線程環(huán)境中的并發(fā)訪問操作的正確性。
- 有序集合:Vector是一個有序集合,可以按照元素的插入順序迭代訪問元素。
- 允許重復(fù)元素:Vector允許存儲重復(fù)的元素,即可以在列表中存儲相同的元素多次。
- 隨機訪問:由于Vector使用基于索引的數(shù)組實現(xiàn),因此可以通過索引進(jìn)行快速的隨機訪問和修改元素??梢允褂胓et(index)方法根據(jù)索引獲取元素,使用set(index, element)方法根據(jù)索引修改元素。
- 動態(tài)修改:Vector提供了一系列方法來動態(tài)修改列表,包括添加元素、刪除元素、插入元素等。常用的方法包括add(element)用于在列表末尾添加元素,remove(element)用于刪除指定元素,add(index, element)用于在指定位置插入元素等。
- 迭代器支持:Vector實現(xiàn)了Iterable接口,因此可以使用迭代器來遍歷列表中的元素??梢酝ㄟ^iterator()方法獲取迭代器,并使用hasNext()和next()方法依次訪問元素。
4.2 Vector 使用案例
demo:
import java.util.Vector; public class VectorExample { public static void main(String[] args) { // 創(chuàng)建一個Vector,用于存儲整數(shù) Vector<Integer> numbers = new Vector<>(); // 添加元素到Vector numbers.add(11); numbers.add(22); numbers.add(33); numbers.add(44); // 獲取Vector的大小 int size = numbers.size(); System.out.println("Vector的大?。? + size); // 訪問指定位置的元素 int element = numbers.get(2); System.out.println("索引2上的元素:" + element); // 修改指定位置的元素 numbers.set(1, 25); System.out.println("修改后的Vector:" + numbers); // 刪除指定位置的元素 int removedElement = numbers.remove(3); System.out.println("被刪除的元素:" + removedElement); System.out.println("刪除后的Vector:" + numbers); // 在特定位置插入元素 numbers.add(0, 5); System.out.println("插入后的Vector:" + numbers); // 檢查Vector是否包含某個元素 boolean contains = numbers.contains(30); System.out.println("Vector是否包含30:" + contains); // 清空Vector numbers.clear(); System.out.println("清空后的Vector:" + numbers); } }
輸出結(jié)果:
Vector的大小:4
索引2上的元素:33
修改后的Vector:[11, 25, 33, 44]
被刪除的元素:44
刪除后的Vector:[11, 25, 33]
插入后的Vector:[5, 11, 25, 33]
Vector是否包含30:false
清空后的Vector:[]
五、Stack
Stack
(棧)是Java集合框架中的一個類,它實現(xiàn)了"后進(jìn)先出"(Last-In-First-Out,LIFO)的數(shù)據(jù)結(jié)構(gòu)。Stack
繼承自Vector
類,因此具有Vector
的所有特性,同時提供了一些額外的棧操作方法。
Stack
的主要用途是在需要后進(jìn)先出操作的場景中,例如在逆序輸出、括號匹配、深度優(yōu)先搜索等算法中常用到。需要注意的是,由于Stack
繼承自Vector
,它具有線程安全的特性,但在性能上可能不如其他非同步的棧實現(xiàn),如ArrayDeque
。因此,在不需要線程安全操作的情況下,可以考慮使用ArrayDeque
代替Stack
。
5.1 Stack 的特點
- 后進(jìn)先出(LIFO):Stack中的元素按照后進(jìn)先出的順序進(jìn)行操作。最后添加的元素將首先被訪問或刪除,而最先添加的元素將最后被訪問或刪除。
- 繼承自Vector:Stack繼承了Vector類的所有功能,包括動態(tài)數(shù)組實現(xiàn)、隨機訪問、動態(tài)修改等。由于Stack是Vector的子類,因此可以使用Vector的所有方法來操作棧。
- 壓棧和出棧:Stack提供了push(element)方法用于將元素壓入棧頂,以及pop()方法用于從棧頂彈出并返回棧頂元素。通過這兩個方法,可以實現(xiàn)棧的基本操作。
- 查看棧頂元素:Stack提供了peek()方法,用于返回但不刪除棧頂元素。這個方法可以用于查看棧頂元素而不改變棧的狀態(tài)。
- 判空和棧大?。篠tack提供了isEmpty()方法來檢查棧是否為空,以及size()方法來獲取棧中元素的數(shù)量。
- 搜索元素:Stack提供了search(element)方法,用于在棧中搜索指定元素,并返回相對于棧頂?shù)木嚯x(如果元素存在于棧中)。如果元素不存在于棧中,則返回-1。
5.2 Stack 使用案例
demo:
import java.util.Stack; public class StackDemo { public static void main(String[] args) { // 創(chuàng)建一個Stack,用于存儲整數(shù) Stack<Integer> stack = new Stack<>(); // 壓入元素到棧頂 stack.push(66); stack.push(88); stack.push(99); // 查看棧頂元素 int topElement = stack.peek(); System.out.println("棧頂元素:" + topElement); // 彈出棧頂元素 int poppedElement = stack.pop(); System.out.println("彈出的元素:" + poppedElement); // 查看棧的大小 int size = stack.size(); System.out.println("棧的大小:" + size); // 判斷棧是否為空 boolean isEmpty = stack.isEmpty(); System.out.println("棧是否為空:" + isEmpty); } }
輸出結(jié)果:
棧頂元素:99
彈出的元素:99
棧的大?。?
棧是否為空:false
六、CopyOnWriteArrayList
CopyOnWriteArrayList
是Java并發(fā)集合框架中的一種線程安全的列表實現(xiàn)。
由于CopyOnWriteArrayList
的寫操作會創(chuàng)建新的副本,因此在多個線程同時進(jìn)行寫操作時,不會發(fā)生數(shù)據(jù)不一致的情況。最終輸出的列表中包含了所有寫線程添加的元素。
注意,由于CopyOnWriteArrayList
的特性,讀取操作不會受到寫操作的影響,因此可以安全地在寫操作進(jìn)行時進(jìn)行讀取操作。
6.1 CopyOnWriteArrayList 的特點
- 線程安全:CopyOnWriteArrayList通過在修改操作時創(chuàng)建一個新的副本來實現(xiàn)線程安全性。這意味著多個線程可以同時進(jìn)行讀取操作,而不會阻塞彼此,且讀取操作不會受到修改操作的影響。
- 寫時復(fù)制:在修改操作(如添加、修改、刪除元素)時,CopyOnWriteArrayList會創(chuàng)建一個數(shù)組的新副本,以保持原有數(shù)組的不可變性。這意味著修改操作不會直接修改原始數(shù)組,而是在新副本上進(jìn)行操作,從而保證了讀取操作的線程安全性。
- 高效的讀取操作:由于讀取操作不需要進(jìn)行同步或加鎖,所以讀取操作的性能很高。適用于讀多寫少的場景。
- 適用于靜態(tài)數(shù)據(jù)集:CopyOnWriteArrayList適用于靜態(tài)數(shù)據(jù)集,即在創(chuàng)建后很少有修改操作。如果需要頻繁進(jìn)行修改操作,可能會產(chǎn)生較高的內(nèi)存開銷,因為每次修改都會創(chuàng)建新的副本。
6.2 CopyOnWriteArrayList 使用案例
demo:
import java.util.concurrent.CopyOnWriteArrayList; public class CopyOnWriteArrayListDemo { public static void main(String[] args) { // 創(chuàng)建一個CopyOnWriteArrayList,用于存儲整數(shù) CopyOnWriteArrayList<Integer> numbers = new CopyOnWriteArrayList<>(); // 創(chuàng)建并啟動多個線程進(jìn)行寫操作 for (int i = 0; i < 5; i++) { int finalI = i; Thread thread = new Thread(() -> { numbers.add(finalI); System.out.println("線程" + Thread.currentThread().getName() + ":添加元素 " + finalI); }); thread.start(); } // 等待所有寫線程執(zhí)行完畢 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 輸出列表中的元素 System.out.println("列表中的元素:" + numbers); } }
輸出結(jié)果:
線程Thread-0:添加元素 0
線程Thread-4:添加元素 4
線程Thread-3:添加元素 3
線程Thread-1:添加元素 1
線程Thread-2:添加元素 2
列表中的元素:[0, 1, 3, 4, 2]
七、總結(jié)
ArrayList、LinkedList、Vector、Stack和CopyOnWriteArrayList都是Java集合框架中的List的實現(xiàn)類,用于存儲有序的元素集合,但它們在底層數(shù)據(jù)結(jié)構(gòu)、線程安全性以及性能特點上存在一些差異。
在實際開發(fā)中我們要根據(jù)業(yè)務(wù)的需求來合理的選擇不同的數(shù)據(jù)結(jié)構(gòu)。
以上就是詳解Java List中五種常見實現(xiàn)類的使用的詳細(xì)內(nèi)容,更多關(guān)于Java List的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
詳解Spring boot+CXF開發(fā)WebService Demo
這篇文章主要介紹了詳解Spring boot+CXF開發(fā)WebService Demo,非常具有實用價值,需要的朋友可以參考下2017-05-05SpringBoot+ECharts是如何實現(xiàn)數(shù)據(jù)可視化的
今天帶大家學(xué)習(xí)的是關(guān)于Java的相關(guān)知識,文章圍繞著SpringBoot+ECharts怎么實現(xiàn)數(shù)據(jù)可視化展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06cmd中javac命令無法運行(java指令能運行)解決步驟
這篇文章主要介紹了在安裝JDK后,執(zhí)行javac命令沒有返回值的問題,可能是由于命令提示符窗口緩存問題、系統(tǒng)路徑優(yōu)先級問題、文件權(quán)限問題或命令行輸入問題,文中通過代碼將解決的步驟介紹的非常詳細(xì),需要的朋友可以參考下2025-02-02關(guān)于json序列化(javaBean轉(zhuǎn)Json的細(xì)節(jié)處理)
這篇文章主要介紹了關(guān)于json序列化(javaBean轉(zhuǎn)Json的細(xì)節(jié)處理),具有很好的參考價值,希望對大家有所幫助。2022-03-03