首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 集合框架核心三大容器:ArrayList、HashSet、HashMap 實戰總結

     編輯:Java 綜合教學

Java 集合框架核心三大容器:ArrayList、HashSet、HashMap 實戰總結

Java 集合框架是數據存儲與操作的利器。本文以記事本為例,演示 ArrayList 有序可重複、HashSet 無序去重、HashMap 鍵值映射三大核心容器的典型用法、內部機制與遍歷技巧,並解析 toString() 打印原理。

一、ArrayList:有序、可重複、動態擴容

記事本實戰代碼

public class Notebook {
    private ArrayList<String> notes = new ArrayList<>(); // 泛型指定 String

    public void add(String s) { notes.add(s); }
    public int getSize() { return notes.size(); }
    public void removeNote(int index) { notes.remove(index); }
    public String getNote(int index) { return notes.get(index); }
    public String[] list() { 
        return notes.toArray(new String[0]); // JDK 11+ 推薦 new String[0]
    }

    public static void main(String[] args) {
        Notebook nb = new Notebook();
        nb.add("first"); nb.add("second");
        System.out.println(nb.getSize()); // 2
        for (String s : nb.list()) System.out.println(s);
    }
}

核心操作複雜度

操作時間複雜度說明
add(E)O(1) 攤還尾部添加,擴容時 O(n)
add(index, E)O(n)需搬移後續元素
get(index)O(1)數組隨機訪問
remove(index)O(n)搬移元素填補空位
contains(E)O(n)線性掃描

擴容機制

  • 默認初始容量 10,擴容 1.5 倍 (newCapacity = old + (old >> 1))。
  • 可預估數據量用 new ArrayList<>(capacity) 避免多次擴容拷貝。

二、HashSet:無序、不可重複、基於 HashMap 實現

特性驗證

Set<String> set = new HashSet<>();
set.add("A"); set.add("B"); set.add("A"); // 重複不添加
System.out.println(set); // [A, B] 順序不固定

底層原理

  • HashSet 內部持有一個 HashMap<E, Object>,所有鍵映射到同一個 PRESENT 虛擬值。
  • 去重依賴 hashCode() 與 equals() 契約:自定義對象作為元素必須重寫這兩個方法。

三、HashMap:鍵值映射、鍵唯一、值可重複

美分轉換器示例

Map<Integer, String> coins = new HashMap<>();
coins.put(1, "penny");
coins.put(5, "nickel");
coins.put(10, "dime");
coins.put(25, "quarter");
coins.put(1, "one cent"); // 鍵 1 覆蓋,值更新為 "one cent"

System.out.println(coins.get(1)); // one cent
System.out.println(coins.size()); // 4

三種遍歷方式 (推薦順序)


// 1. entrySet - 最通用,同時獲取鍵值 (推薦)
for (Map.Entry<Integer, String> entry : coins.entrySet()) {
    System.out.println(entry.getKey() + " -> " + entry.getValue());
}

// 2. keySet + get - 需額外查找值,稍慢
for (Integer key : coins.keySet()) {
    System.out.println(key + " -> " + coins.get(key));
}

// 3. forEach (JDK 8+) - 函數式風格,代碼簡潔
coins.forEach((k, v) -> System.out.println(k + " -> " + v));

核心參數與擴容

  • 默認負載因子 0.75,閾值 = 容量 × 0.75。
  • 鍵的 hashCode() 決定桶位置,equals() 解決哈希衝突。
  • JDK 8 鏈表轉紅黑樹 (閾值 8),退化為樹結構保證 O(log n) 查找。

四、容器打印之謎:為什麼 System.out.println(list) 直接輸出內容?

集合框架所有實現類 (ArrayList, HashSet, HashMap 等) 繼承自 AbstractCollection,覆寫了 toString():

// AbstractCollection.toString() 簡化版
public String toString() {
    Iterator<E> it = iterator();
    if (!it.hasNext()) return "[]";
    StringBuilder sb = new StringBuilder();
    sb.append('[');
    for (;;) {
        E e = it.next();
        sb.append(e == this ? "(this Collection)" : String.valueOf(e));
        if (!it.hasNext()) return sb.append(']').toString();
        sb.append(',').append(' ');
    }
}

結論:集合打印本質是迭代調用每個元素的 toString()。自定義類若想友好打印,**必須重寫 toString()**。

五、選型決策表

需求推薦容器關鍵點
頻繁隨機訪問、尾部增刪、允許重複ArrayList預設容量、避免中間插入
頻繁頭部/中間增刪、順序訪問LinkedList雙向鏈表、實現 Deque
去重、無序、快速判斷存在性HashSet重寫 hashCode/equals
有序去重 (插入序/自然序)LinkedHashSet / TreeSetTreeSet 需實現 Comparable
鍵值映射、鍵唯一、高頻查找HashMap鍵不可變、預估容量
有序映射 (插入序/鍵排序)LinkedHashMap / TreeMapTreeMap 鍵需 Comparable
多線程高併發ConcurrentHashMap / CopyOnWriteArrayList分段鎖 / 寫時復制

六、避坑指南

  1. ❌ new ArrayList<>(1000000) 顯式指定大容量可能 OOM,建議分批處理或用流式 API。
  2. ❌ 在 foreach 中直接 list.remove() → ConcurrentModificationException,請用 Iterator.remove() 或 removeIf()。
  3. ❌ 自定義對象作為 HashMap 鍵/HashSet 元素未重寫 hashCode/equals → 無法正確去重/查找。
  4. ❌ 使用 HashMap 存儲大量長期存活對象導致內存洩漏,考慮 WeakHashMap 或定期清理。
  5. ✅ JDK 9+ 使用 List.of(), Set.of(), Map.of() 創建不可變集合,線程安全且內存緊湊。

掌握三大容器的底層數據結構 (動態數組、哈希表、紅黑樹) 與核心契約 (hashCode/equals),就能在面對海量業務場景時,憑直覺選出最優容器,寫出高性能、低 Bug 的代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved