Java-List集合類全面解析

Java-List集合類全面解析

  • 前言
  • 一、List接口概述與核心特性
    • 1.1 List在集合框架中的位置
    • 1.2 List的核心特性
    • 1.3 常見實現類對比
  • 二、ArrayList源碼剖析與應用場景
    • 2.1 內部結構與初始化
    • 2.2 動態擴容機制
    • 2.3 性能特點與最佳實踐
  • 三、LinkedList 源碼剖析與應用場景
    • 3.1 內部結構與節點定義
    • 3.2 核心操作實現
    • 3.3 與 ArrayList 的性能對比
  • 四、線程安全的 List 實現
    • 4.1 Vector 的使用與局限性
    • 4.2 CopyOnWriteArrayList 原理
    • 4.3 適用場景對比
  • 五、List 的高級應用技巧
    • 5.1 不可變 List 的創建
    • 5.2 List 的排序操作
    • 5.3 列表轉換與過濾(Java 8+)
  • 六、常見問題與解決方案
    • 6.1 并發修改異常(ConcurrentModificationException)
    • 6.2 性能優化建議
  • 七、List 類的典型應用場景
    • 7.1 數據緩存
    • 7.2 任務隊列
    • 7.3 線程安全配置中心
  • 總結

前言

Java中集合框架是數據處理的核心工具之一,List作為單列集合Collection的重要子接口,憑借其有序、可重復的特性,成為日常開發中使用頻率極高的組件。本文將從基礎概念入手,深入剖析List接口及其實現類的內部機制、應用場景與最佳實踐,并結合大量代碼示例幫助讀者全面掌握這一核心知識點。

一、List接口概述與核心特性

1.1 List在集合框架中的位置

Java集合框架主要分為兩大體系:單列集合Collection和雙列集合MapList作為Collection的直接子接口,繼承了Collection的基本操作,并額外提供了基于索引的訪問能力。其繼承關系如下:

java.lang.Object? java.util.Collection<E>? java.util.List<E>

1.2 List的核心特性

與其他Collection接口相比,List具有以下顯著特點:

  1. 有序性:元素按照插入順序排列,可以通過索引精確訪問

  2. 可重復性:允許存儲重復元素

  3. 索引支持:提供基于0的整數索引操作元素

  4. 豐富的操作方法:新增了add(index, element)get(index)remove(index)等索引相關方法

1.3 常見實現類對比

實現類數據結構線程安全特點
ArrayList動態數組隨機訪問快,插入刪除慢,默認容量10,擴容因子1.5
LinkedList雙向鏈表插入刪除快,隨機訪問慢,實現了`Deque`接口
Vector動態數組線程安全但性能較低,擴容因子2
CopyOnWriteArrayList寫時復制數組讀操作無鎖,寫操作復制數組,適用于讀多寫少場景

二、ArrayList源碼剖析與應用場景

2.1 內部結構與初始化

ArrayList的核心是一個動態擴容的Object數組:

transient Object[] elementData; // 存儲元素的數組
private int size; // 實際元素數量

初始化時可指定初始容量:

// 默認構造器,初始為空數組,首次添加元素時擴容為10
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}// 指定初始容量
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];}
}

2.2 動態擴容機制

當元素數量超過數組容量時,會觸發擴容操作:

private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 擴容為原容量的1.5倍if (newCapacity - minCapacity < 0)newCapacity = minCapacity;elementData = Arrays.copyOf(elementData, newCapacity);
}

2.3 性能特點與最佳實踐

  • 優勢場景:頻繁隨機訪問、較少插入刪除操作

  • 注意事項

    • 初始容量設置:預計元素數量較大時,建議指定合理初始容量減少擴容次數

    • 避免中間插入刪除:此類操作會導致后續元素整體移動,時間復雜度 O (n)

// 示例:預分配容量提高性能
ArrayList<String> list = new ArrayList<>(1000);
for (int i = 0; i < 1000; i++) {list.add("element" + i); // 避免多次擴容
}

三、LinkedList 源碼剖析與應用場景

3.1 內部結構與節點定義

LinkedList 基于雙向鏈表實現,每個節點包含前驅和后繼引用:

private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

3.2 核心操作實現

插入操作僅需修改前后節點引用:

// 在指定位置插入元素
void linkBefore(E e, Node<E> succ) {final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;
}

3.3 與 ArrayList 的性能對比

操作類型 ArrayList 時間復雜度 LinkedList 時間復雜度
隨機訪問 get (i) O(1) O(n)
尾部插入 add (e) O (1)(可能擴容) O(1)
中間插入 add (i,e) O (n)(元素移動) O (n/2)(定位節點)
刪除指定元素 remove (e) O (n)(查找 + 移動) O (n)(查找)

四、線程安全的 List 實現

4.1 Vector 的使用與局限性

Vector 是早期的線程安全 List 實現,所有公共方法都使用synchronized修飾:

public synchronized E get(int index) {if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);return elementData(index);
}

但這種粗粒度同步導致性能較差,現代開發中已較少使用。

4.2 CopyOnWriteArrayList 原理

采用寫時復制策略,寫操作會創建新數組:

public boolean add(E e) {final ReentrantLock lock = this.lock;lock.lock();try {Object[] elements = getArray();int len = elements.length;Object[] newElements = Arrays.copyOf(elements, len + 1);newElements[len] = e;setArray(newElements);return true;} finally {lock.unlock();}
}

4.3 適用場景對比

  • Vector:適用于遺留系統,需要全面線程安全保證

  • CopyOnWriteArrayList:適用于讀多寫少場景,如配置中心、事件監聽器列表

五、List 的高級應用技巧

5.1 不可變 List 的創建

使用Collections.unmodifiableList或 Java 9 + 的List.of創建不可變列表:

// Java 9+
List<String> immutableList = List.of("a", "b", "c");// 基于現有列表創建
List<String> original = new ArrayList<>();
List<String> unmodifiable = Collections.unmodifiableList(original);

5.2 List 的排序操作

使用Collections.sortList.sort方法:

// 自然排序
list.sort(Comparator.naturalOrder());// 自定義排序
list.sort((e1, e2) -> e1.getName().compareTo(e2.getName()));

5.3 列表轉換與過濾(Java 8+)

利用 Stream API 進行轉換和過濾:

List<String> names = people.stream().filter(p -> p.getAge() > 18).map(Person::getName).collect(Collectors.toList());

六、常見問題與解決方案

6.1 并發修改異常(ConcurrentModificationException)

在使用迭代器遍歷 List 時修改結構會拋出此異常,解決方案:

  • 使用Iterator.remove()方法

  • 使用CopyOnWriteArrayList

  • 使用 for 循環倒序遍歷

// 安全刪除示例
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {String item = it.next();if (condition) {it.remove(); // 安全刪除}
}

6.2 性能優化建議

  • 對于 ArrayList,預估容量避免頻繁擴容

  • 避免在 LinkedList 中使用隨機訪問

  • 批量操作優先使用addAll而非循環添加

七、List 類的典型應用場景

7.1 數據緩存

使用 ArrayList 存儲熱點數據,利用其快速隨機訪問特性:

public class DataCache {private final List<Data> cache = new ArrayList<>();public Data getById(int id) {return cache.get(id); // O(1)訪問}
}

7.2 任務隊列

使用 LinkedList 實現 FIFO 隊列:

public class TaskQueue {private final LinkedList<Runnable> queue = new LinkedList<>();public synchronized void enqueue(Runnable task) {queue.addLast(task);}public synchronized Runnable dequeue() {return queue.pollFirst();}
}

7.3 線程安全配置中心

使用 CopyOnWriteArrayList 存儲配置項:

public class ConfigCenter {private final CopyOnWriteArrayList<ConfigItem> configs = new CopyOnWriteArrayList<>();public void addConfig(ConfigItem item) {configs.add(item); // 寫操作線程安全}public List<ConfigItem> getAllConfigs() {return new ArrayList<>(configs); // 讀操作無鎖}
}

總結

根據情況選擇合適的 List 實現

  • 需要快速隨機訪問:ArrayList

  • 需要頻繁插入刪除:LinkedList

  • 需要線程安全:CopyOnWriteArrayList(讀多寫少)或 Vector(全同步)

通過深入理解 List 接口及其實現類的內部機制和應用場景,我們可以更加高效地使用這一核心工具,編寫出性能優異、結構清晰的代碼。希望本文能夠幫助讀者全面掌握 Java List 類的使用技巧,在實際開發中發揮更大的價值。

若這篇內容幫到你,動動手指支持下!關注不迷路,干貨持續輸出!
ヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノヾ(′? ˋ)ノ

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/81554.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/81554.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/81554.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Flink 并行度的設置

在 Apache Flink 中&#xff0c;并行度&#xff08;Parallelism&#xff09; 是控制任務并發執行的核心參數之一。Flink 提供了 多個層級設置并行度的方式&#xff0c;優先級從高到低如下&#xff1a; &#x1f9e9; 一、Flink 并行度的四個設置層級 層級描述設置方式Operator…

OpenCV 筆記(39):頻域中的拉普拉斯算子

1. 拉普拉斯算子 在該系列的第八篇文章中&#xff0c;我們曾經介紹過在二維空間拉普拉斯算子的定義為&#xff1a; 這是對函數 的二階偏導數之和。 2. 拉普拉斯算子的傅里葉變換及其推導 在該系列的第三十二篇文章中&#xff0c;我們曾給介紹過下面的公式 二維連續傅里葉變換&…

入職軟件開發與實施工程師了后........

時隔幾個月沒有創作的我又回來了&#xff0c;這幾個月很忙&#xff0c;我一直在找工作&#xff0c;在自考&#xff08;順便還處理了一下分手的事&#xff09;&#xff0c;到處奔波&#xff0c;心力交瘁。可能我骨子里比較傲吧。我不愿意著急謀生&#xff0c;做我不愿意做的普通…

多卡跑ollama run deepseek-r1

# 設置環境變量并啟動模型 export CUDA_VISIBLE_DEVICES0,1,2,3 export OLLAMA_SCHED_SPREAD1 # 啟用多卡負載均衡 ollama run deepseek-r1:32b 若 deepseek-r1:32b 的顯存需求未超過單卡容量&#xff08;如單卡 24GB&#xff09;&#xff0c;Ollama 不會自動啟用多卡 在run…

09、底層注解-@Import導入組件

09、底層注解-Import導入組件 Import是Spring框架中的一個注解&#xff0c;用于將組件導入到Spring的應用上下文中。以下是Import注解的詳細介紹&#xff1a; #### 基本用法 - **導入配置類** java Configuration public class MainConfig { // 配置內容 } Configuration Impo…

題解:P12207 [藍橋杯 2023 國 Python B] 劃分

鏈接 題目描述 給定 40 個數&#xff0c;請將其任意劃分成兩組&#xff0c;每組至少一個元素。每組的權值為組內所有元素的和。劃分的權值為兩組權值的乘積。請問對于以下 40 個數&#xff0c;劃分的權值最大為多少。 5160 9191 6410 4657 7492 1531 8854 1253 4520 9231126…

配置ssh服務-ubuntu到Windows拷貝文件方法

背景&#xff1a; 在工作中&#xff0c;需要頻繁從ubuntu到Windows拷貝文件&#xff0c;但有時間總是無法拷出&#xff0c;每次重啟虛擬機又比較麻煩并且效率較低。可以使用scp服務進行拷貝&#xff0c;不僅穩定而且高效&#xff0c;現將配置過程進行梳理&#xff0c;以供大家參…

線程池模式與C#中用法

一、線程池模式解析 1. 核心概念 線程池是一種 管理線程生命周期的技術&#xff0c;主要解決以下問題&#xff1a; 減少線程創建/銷毀開銷&#xff1a;復用已存在的線程 控制并發度&#xff1a;避免無限制創建線程導致資源耗盡 任務隊列&#xff1a;有序處理異步請求 2. …

設置IDEA打開新項目使用JDK17

由于最近在學習Spring-AI&#xff0c;所以JDK8已經不適用了&#xff0c;但是每次創建新項目都還是JDK8&#xff0c;每次調來調去很麻煩 把Projects和SDKs都調整為JDK17即可 同時&#xff0c;Maven也要做些更改&#xff0c;主要是添加build標簽 <build><plugins>&…

初識MySQL · 索引

目錄 前言&#xff1a; 重溫磁盤 認識索引 為什么這么做&#xff0c;怎么做 重談page 聚簇索引VS非聚簇索引 回表查詢 索引分類 前言&#xff1a; 前文我們主要是介紹了MySQL的一些基本操作&#xff0c;增刪查改一類的操作都介紹了&#xff0c;并且因為大多數情況下&am…

MySQL——7、復合查詢和表的內外連接

復合查詢和表的內外連接 1、基本查詢回顧2、多表查詢3、自連接4、子查詢4.1、單行子查詢4.2、多行子查詢4.3、多列子查詢4.4、在from子句中使用子查詢4.5、合并查詢 5、表的內連和外連5.1、內連接5.2、外連接5.2.1、左外連接5.2.2、右外連接 1、基本查詢回顧 1.1、查詢工資高于…

MYSQL故障排查和環境優化

一、MySQL故障排查 1. 單實例常見故障 &#xff08;1&#xff09;連接失敗類問題 ERROR 2002 (HY000): Cant connect to MySQL server 原因&#xff1a;MySQL未啟動或端口被防火墻攔截。 解決&#xff1a;啟動MySQL服務&#xff08;systemctl start mysqld&#xff09;或開放…

7GB顯存如何部署bf16精度的DeepSeek-R1 70B大模型?

構建RAG混合開發---PythonAIJavaEEVue.js前端的實踐-CSDN博客 服務容錯治理框架resilience4j&sentinel基礎應用---微服務的限流/熔斷/降級解決方案-CSDN博客 conda管理python環境-CSDN博客 快速搭建對象存儲服務 - Minio&#xff0c;并解決臨時地址暴露ip、短鏈接請求改…

數字圖像處理——圖像壓縮

背景 圖像壓縮是一種減少圖像文件大小的技術&#xff0c;旨在在保持視覺質量的同時降低存儲和傳輸成本。隨著數字圖像的廣泛應用&#xff0c;圖像壓縮在多個領域如互聯網、移動通信、醫學影像和衛星圖像處理中變得至關重要。 技術總覽 當下圖像壓縮JPEG幾乎一統天下&#xff…

抖音視頻怎么去掉抖音號水印

你是不是經常遇到這樣的煩惱&#xff1f;看到喜歡的抖音視頻&#xff0c;想保存下來分享給朋友或二次創作&#xff0c;卻被抖音號水印擋住了畫面&#xff1f;別著急&#xff0c;今天教你幾種超簡單的方法&#xff0c;輕松去除水印&#xff0c;高清無水印視頻一鍵保存&#xff0…

RISC-V 開發板 MUSE Pi Pro PCIE 測試以及 fio 崩潰問題解決

視頻講解&#xff1a; RISC-V 開發板 MUSE Pi Pro PCIE 測試以及 fio 崩潰問題解決 板子上有一個m.2的pcie插槽&#xff0c;k1有三個pcie控制器&#xff0c;pcie0和usb3復用一個phy&#xff0c;所以實際開發板就兩個&#xff0c;測試的話&#xff0c;上一個nvme硬盤&#xff0c…

超級管理員租戶資源初始化與授權管理設計方案

背景說明 在多租戶系統中&#xff0c;資源&#xff08;如功能模塊、系統菜單、服務能力等&#xff09;需按租戶維度進行授權管理。超級管理員在創建新租戶時&#xff0c;需要初始化該租戶的資源授權信息。 兩種可選方案 方案描述方案 A&#xff1a;前端傳入選中的資源列表創…

stm32week16

stm32學習 十一.中斷 4.使用中斷 EXTI的配置步驟&#xff1a; 使能GPIO時鐘設置GPIO輸入模式使能AFIO/SYSCFG時鐘設置EXTI和IO對應關系設置EXTI屏蔽&#xff0c;上/下沿設置NVIC設計中斷服務函數 HAL庫的使用&#xff1a; 使能GPIO時鐘&#xff1a;__HAL_RCC_GPIOx_CLK_EN…

什么是RDMA?

什么是RDMA&#xff1f; RDMA(RemoteDirect Memory Access)技術全稱遠程直接內存訪問&#xff0c;就是為了解決網絡傳輸中服務器端數據處理的延遲而產生的。它將數據直接從一臺計算機的內存傳輸到另一臺計算機&#xff0c;無需雙方操作系統的介入。這允許高吞吐、低延遲的網絡…

golang 安裝gin包、創建路由基本總結

文章目錄 一、安裝gin包和熱加載包二、路由簡單場景總結 一、安裝gin包和熱加載包 首先終端新建一個main.go然后go mod init ‘項目名稱’執行以下命令 安裝gin包 go get -u github.com/gin-gonic/gin終端安裝熱加載包 go get github.com/pilu/fresh終端輸入fresh 運行 &…