📚 Java集合框架解析:List與ArrayList的完美結合
🌟 前言:為什么我們需要List和ArrayList?
在日常開發中,我們經常需要處理一組數據。想象一下,如果你要管理一個班級的學生名單,或者處理電商網站的商品列表,你會怎么做?Java集合框架中的List和ArrayList就是為解決這類問題而生的利器!
本文將帶你深入探索List接口和ArrayList實現類的奧秘,通過豐富的示例和直觀的圖示,讓你徹底掌握它們的用法和原理。
🧩 第一部分:List接口全景圖
1. 什么是List?
List是Java集合框架中的一個接口,它繼承自Collection接口,代表一個有序的、可重復的元素序列。
public interface List<E> extends Collection<E> {// 一系列方法定義
}
🎯 List的核心特性:
- 有序性:元素按照插入順序排列
- 可重復:允許存儲相同的元素
- 索引訪問:可以通過下標直接訪問元素
2. List的繼承體系(思維導圖)
3. List常用方法速查表
方法簽名 | 功能描述 | 時間復雜度 |
---|---|---|
boolean add(E e) | 尾部添加元素 | O(1) |
void add(int index, E element) | 指定位置插入 | O(n) |
E get(int index) | 獲取指定位置元素 | O(1) |
E set(int index, E element) | 修改指定位置元素 | O(1) |
E remove(int index) | 刪除指定位置元素 | O(n) |
int size() | 返回元素個數 | O(1) |
boolean contains(Object o) | 判斷是否包含元素 | O(n) |
🚀 第二部分:ArrayList深度剖析
1. ArrayList的底層原理
ArrayList是基于動態數組實現的順序表,它自動處理擴容問題,讓我們可以專注于業務邏輯。
// 底層核心數組
transient Object[] elementData;
// 實際元素數量
private int size;
2. ArrayList的構造方法對比
構造方法 | 說明 | 初始容量 |
---|---|---|
ArrayList() | 無參構造 | 10 |
ArrayList(int initialCapacity) | 指定初始容量 | 自定義 |
ArrayList(Collection<? extends E> c) | 從集合構造 | 集合大小 |
3. 動態擴容機制揭秘(流程圖)
擴容規則:
- 首次添加元素時擴容到10
- 后續按1.5倍增長(
int newCapacity = oldCapacity + (oldCapacity >> 1)
)
4. ArrayList的三種遍歷方式
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));// 1. for循環+下標
for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));
}// 2. 增強for循環
for (String s : list) {System.out.println(s);
}// 3. 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {System.out.println(it.next());
}
實戰應用:撲克牌游戲
🃏1. 撲克牌游戲:買牌、洗牌、發牌完整實現
// 定義一個Card類來表示一張撲克牌
public class Card {// 定義一個整數類型的變量rank,用于表示牌的面值public int rank; // 定義一個字符串類型的變量suit,用于表示牌的花色public String suit; // 重寫toString方法,用于將Card對象以特定格式輸出@Overridepublic String toString() {// 格式化輸出牌的花色和面值return String.format("[%s %d]", suit, rank); }
}// 導入List接口,用于存儲和操作元素列表
import java.util.List;
// 導入ArrayList類,用于創建動態數組
import java.util.ArrayList;
// 導入Random類,用于生成隨機數
import java.util.Random; // 定義一個CardDemo類,用于演示撲克牌的操作
public class CardDemo {// 定義一個字符串數組SUITS,包含四種花色public static final String[] SUITS = {"?", "?", "?", "?"}; // 定義一個靜態方法buyDeck,用于創建一副完整的撲克牌private static List<Card> buyDeck() {// 創建一個容量為52的ArrayList對象,用于存儲撲克牌List<Card> deck = new ArrayList<>(52); // 外層循環遍歷四種花色for (int i = 0; i < 4; i++) { // 內層循環遍歷1到13的牌面值for (int j = 1; j <= 13; j++) { // 獲取當前花色String suit = SUITS[i]; // 獲取當前牌面值int rank = j; // 創建一個Card對象Card card = new Card(); // 設置Card對象的牌面值card.rank = rank; // 設置Card對象的花色card.suit = suit; // 將Card對象添加到deck列表中deck.add(card); }}// 返回包含所有撲克牌的列表return deck; }// 定義一個靜態方法swap,用于交換列表中兩個位置的元素private static void swap(List<Card> deck, int i, int j) {// 獲取索引i位置的Card對象Card t = deck.get(i); // 將索引j位置的Card對象賦值給索引i位置deck.set(i, deck.get(j)); // 將臨時變量t(原索引i位置的Card對象)賦值給索引j位置deck.set(j, t); }// 定義一個靜態方法shuffle,用于洗牌private static void shuffle(List<Card> deck) {// 創建一個Random對象,使用固定的種子值,保證每次運行結果一致Random random = new Random(20190905); // 從列表的最后一個元素開始向前遍歷for (int i = deck.size() - 1; i > 0; i--) { // 生成一個0到i之間的隨機整數int r = random.nextInt(i); // 調用swap方法交換索引i和r位置的元素swap(deck, i, r); }}// 程序的入口點public static void main(String[] args) {// 調用buyDeck方法創建一副撲克牌List<Card> deck = buyDeck(); // 打印提示信息,表示剛買回來的牌System.out.println("剛買回來的牌:"); // 打印剛買回來的撲克牌列表System.out.println(deck); // 調用shuffle方法對撲克牌進行洗牌shuffle(deck); // 打印提示信息,表示洗過的牌System.out.println("洗過的牌:"); // 打印洗過的撲克牌列表System.out.println(deck); // 創建一個二維列表hands,用于存儲三個玩家的手牌List<List<Card>> hands = new ArrayList<>(); // 為每個玩家創建一個空的手牌列表,并添加到hands中hands.add(new ArrayList<>()); hands.add(new ArrayList<>()); hands.add(new ArrayList<>()); // 模擬每個玩家輪流抓5張牌的過程for (int i = 0; i < 5; i++) { // 遍歷三個玩家for (int j = 0; j < 3; j++) { // 從deck列表中移除第一張牌,并添加到當前玩家的手牌列表中hands.get(j).add(deck.remove(0)); }}// 打印提示信息,表示剩余的牌System.out.println("剩余的牌:"); // 打印剩余的撲克牌列表System.out.println(deck); // 打印提示信息,表示A玩家手中的牌System.out.println("A手中的牌:"); // 打印A玩家的手牌列表System.out.println(hands.get(0)); // 打印提示信息,表示B玩家手中的牌System.out.println("B手中的牌:"); // 打印B玩家的手牌列表System.out.println(hands.get(1)); // 打印提示信息,表示C玩家手中的牌System.out.println("C手中的牌:"); // 打印C玩家的手牌列表System.out.println(hands.get(2)); }
}
🔺2. 楊輝三角生成器(leetcode118)
public List<List<Integer>> generate(int numRows) {List<List<Integer>> triangle = new ArrayList<>();for (int i = 0; i < numRows; i++) {List<Integer> row = new ArrayList<>();for (int j = 0; j <= i; j++) {if (j == 0 || j == i) {row.add(1);} else {row.add(triangle.get(i-1).get(j-1) + triangle.get(i-1).get(j));}}triangle.add(row);}return triangle;}
💡 性能優化與思考
ArrayList的優缺點分析
? 優點:
- 隨機訪問速度快(O(1))
- 內存連續,緩存友好
- 尾部操作高效
? 缺點:
- 中間插入/刪除效率低(O(n))
- 擴容有性能開銷
- 可能造成內存浪費
替代方案考慮
場景 | 推薦結構 | 原因 |
---|---|---|
頻繁隨機訪問 | ArrayList | O(1)訪問 |
頻繁插入刪除 | LinkedList | O(1)插入刪除 |
多線程環境 | CopyOnWriteArrayList | 線程安全 |
固定大小 | Arrays.asList() | 不可變 |
📌 總結與面試必備
- List vs ArrayList:List是接口,ArrayList是實現
- 擴容機制:初始10,1.5倍增長
- 時間復雜度:
- 訪問:O(1)
- 搜索:O(n)
- 插入/刪除:平均O(n)
- 線程安全:ArrayList非線程安全,多線程需同步
🎁 彩蛋:ArrayList的趣味事實
你知道嗎?ArrayList在JDK1.2中引入,它的設計受到了C++ STL中vector的啟發。但在Java中,為了避免與數學向量概念混淆,才命名為ArrayList!
希望這篇深度解析能幫助你徹底掌握List和ArrayList!如果有任何問題,歡迎在評論區留言討論。別忘了點贊收藏哦~ 💖