Java 集合框架详解

Java 集合框架(Collection Framework)是 Java 中用来存储、管理和操作数据的一套标准化体系,就像现实生活中的 “容器”—— 不同的容器适合存放不同类型的数据,操作效率也各有侧重。它将复杂的数据结构(如数组、链表、哈希表等)封装成易用的类,开发者无需关注底层实现,只需调用现成的方法即可完成数据的增删改查。

一、集合框架的 “家族图谱”

Java 集合框架的核心是 Collection 和 Map 两大接口,它们之下衍生出众多实现类,覆盖了几乎所有常用的数据结构场景。整体结构可简化为:
 
Java 集合框架
├─ Collection(单元素集合:存储单个值)
│  ├─ List(有序、可重复)
│  │  ├─ ArrayList(动态数组实现)
│  │  ├─ LinkedList(双向链表实现)
│  │  └─ Vector(线程安全的动态数组,古老类)
│  ├─ Set(无序、不可重复)
│  │  ├─ HashSet(哈希表实现)
│  │  ├─ TreeSet(红黑树实现,自动排序)
│  │  └─ LinkedHashSet(哈希表+链表,保留插入顺序)
│  └─ Queue(队列:先进先出FIFO)
│     ├─ LinkedList(链表实现,常用作队列)
│     └─ PriorityQueue(优先级队列,按元素大小排序)
└─ Map(键值对集合:存储“键-值”映射)
   ├─ HashMap(哈希表实现,无序)
   ├─ TreeMap(红黑树实现,键自动排序)
   ├─ LinkedHashMap(哈希表+链表,保留插入顺序)
   └─ Hashtable(线程安全的哈希表,古老类)
 

二、Collection 接口:单元素集合的 “通用规则”

Collection 是所有单元素集合的根接口,定义了一套通用方法(如添加、删除、遍历元素),其子接口 ListSetQueue 在此基础上扩展出各自的特性。

1. List:有序可重复的 “动态数组”

List 集合的核心特点是 “有序”(元素有固定的索引位置,像数组一样按顺序存储)和 “可重复”(允许添加相同的元素)。
(1)ArrayList:查询快、增删中间慢
  • 底层结构动态数组(长度可变的数组,当元素满时自动扩容为原来的 1.5 倍)。
  • 核心优势:通过索引(如 get(0))访问元素极快(时间复杂度 O(1)),适合频繁查询的场景。
  • 核心劣势:在中间位置插入 / 删除元素时,需要移动后续元素(时间复杂度 O(n)),效率较低。
  • 类比:像一本按页码排序的书,查第 100 页很容易,但在第 50 页插入一页,后面的页码都要重新编排。
    代码示例:
     
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            // 添加元素(有序,可重复)
            list.add("苹果");
            list.add("香蕉");
            list.add("苹果"); // 允许重复
            
            // 按索引访问(0开始)
            System.out.println(list.get(1)); // 输出:香蕉
            
            // 遍历(顺序与添加一致)
            for (String fruit : list) {
                System.out.println(fruit); // 苹果、香蕉、苹果
            }
        }
    }
    
     
(2)LinkedList:增删中间快、查询慢
  • 底层结构双向链表(每个元素包含 “前驱” 和 “后继” 指针,像铁链一样串联)。
  • 核心优势:在中间位置插入 / 删除元素时,只需修改前后元素的指针(时间复杂度 O(1)),适合频繁增删的场景。
  • 核心劣势:查询元素时需从头遍历到目标位置(时间复杂度 O(n)),效率较低。
  • 类比:像一串项链,拆中间的珠子只需解开两边的线,但要找第 100 颗珠子,必须从第一颗开始数。
    代码示例(特有方法):
     
    import java.util.LinkedList;
    
    public class Test {
        public static void main(String[] args) {
            LinkedList<String> list = new LinkedList<>();
            list.add("A");
            list.add("B");
            
            // 链表特有的首尾操作(效率极高)
            list.addFirst("头"); // 开头添加
            list.addLast("尾");  // 结尾添加
            
            System.out.println(list.getFirst()); // 头
            System.out.println(list.getLast());  // 尾
        }
    }
    
     

2. Set:无序不可重复的 “去重容器”

Set 集合的核心特点是 “无序”(元素没有固定位置,遍历顺序与添加顺序无关)和 “不可重复”(添加重复元素会被自动过滤)。
(1)HashSet:去重快、无序
  • 底层结构哈希表(数组 + 链表 / 红黑树,通过元素的 hashCode() 计算存储位置)。
  • 核心优势:添加、删除、查询元素的效率极高(平均时间复杂度 O(1)),适合快速去重场景。
  • 去重原理:依赖元素的 hashCode() 和 equals() 方法 —— 两个元素若 hashCode() 不同,必不重复;若 hashCode() 相同,再通过 equals() 确认是否真的重复。
  • 注意:存储自定义对象时,必须重写 hashCode() 和 equals(),否则无法正确去重。
    代码示例:
     
    import java.util.HashSet;
    import java.util.Set;
    
    public class Test {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            set.add("苹果");
            set.add("香蕉");
            set.add("苹果"); // 重复元素,自动过滤
            
            // 遍历(顺序与添加顺序无关)
            for (String fruit : set) {
                System.out.println(fruit); // 苹果、香蕉(无重复)
            }
        }
    }
    
     
(2)TreeSet:去重 + 自动排序
  • 底层结构红黑树(一种自平衡的二叉排序树,元素会按大小自动排序)。
  • 核心优势:自动按元素大小排序(如数字从小到大、字符串按字典序),同时去重,适合 “排序 + 去重” 场景(如排行榜)。
  • 排序规则:元素需实现 Comparable 接口(重写 compareTo() 方法),或创建 TreeSet 时传入 Comparator 比较器。
    代码示例:
     
    import java.util.TreeSet;
    
    public class Test {
        public static void main(String[] args) {
            TreeSet<Integer> set = new TreeSet<>();
            set.add(3);
            set.add(1);
            set.add(2);
            set.add(3); // 重复元素,自动过滤
            
            System.out.println(set); // 输出:[1, 2, 3](自动排序)
        }
    }
    
     

3. Queue:先进先出的 “排队容器”

Queue 集合遵循 “先进先出(FIFO)” 规则,就像现实中排队买票 —— 先到的人先处理。
LinkedList:常用的队列实现
LinkedList 同时实现了 List 和 Queue 接口,因此常用作队列:
 
 
import java.util.LinkedList;
import java.util.Queue;

public class Test {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<>();
        // 入队(添加到队尾)
        queue.offer("第一个人");
        queue.offer("第二个人");
        
        // 出队(移除并返回队头)
        System.out.println(queue.poll()); // 第一个人(先入先出)
        System.out.println(queue.poll()); // 第二个人
    }
}
 
PriorityQueue:优先级队列(不遵循 FIFO)
元素按 “优先级” 排序,每次出队的是优先级最高的元素(如数字默认按从小到大):
 
 
import java.util.PriorityQueue;
import java.util.Queue;

public class Test {
    public static void main(String[] args) {
        Queue<Integer> pq = new PriorityQueue<>();
        pq.offer(3);
        pq.offer(1);
        pq.offer(2);
        
        System.out.println(pq.poll()); // 1(优先级最高)
        System.out.println(pq.poll()); // 2
    }
}
 

三、Map 接口:键值对集合的 “字典容器”

Map 集合存储的是 “键(Key)- 值(Value)” 对,就像字典中 “单词 - 解释” 的对应关系 —— 通过 “键” 可以快速找到对应的 “值”。

  • 键(Key):唯一不可重复(类似 Set 的元素);
  • 值(Value):可以重复;
  • 一个键只能对应一个值(若添加相同的键,会覆盖旧值)。

1. HashMap:键值对存储的 “效率之王”

  • 底层结构哈希表(JDK1.8 后为 “数组 + 链表 + 红黑树”—— 当链表长度超过 8 时转为红黑树,优化查询效率)。
  • 核心优势:根据键查询值的效率极高(平均时间复杂度 O(1)),适合频繁的 “存、取” 操作。
  • 注意:键的去重逻辑与 HashSet 一致,依赖 hashCode() 和 equals() 方法。
    代码示例:
     
    import java.util.HashMap;
    import java.util.Map;
    
    public class Test {
        public static void main(String[] args) {
            Map<String, Integer> scoreMap = new HashMap<>();
            // 存键值对
            scoreMap.put("张三", 90);
            scoreMap.put("李四", 85);
            scoreMap.put("张三", 95); // 键重复,覆盖旧值
            
            // 查值(通过键)
            System.out.println(scoreMap.get("李四")); // 85
            
            // 遍历所有键值对
            for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue()); 
                // 输出:张三:95、李四:85(顺序不确定)
            }
        }
    }
    
     

2. TreeMap:键自动排序的 “有序字典”

  • 底层结构红黑树,键会按大小自动排序(如数字从小到大、字符串按字典序)。
  • 适合场景:需要按键排序的场景(如按学号排序的成绩表、按日期排序的日志)。
    代码示例:
     
    import java.util.TreeMap;
    
    public class Test {
        public static void main(String[] args) {
            TreeMap<Integer, String> studentMap = new TreeMap<>();
            studentMap.put(3, "张三");
            studentMap.put(1, "李四");
            studentMap.put(2, "王五");
            
            // 遍历(键自动排序)
            for (Map.Entry<Integer, String> entry : studentMap.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue()); 
                // 输出:1:李四、2:王五、3:张三
            }
        }
    }
    
     

四、集合框架的 “通用工具”

1. 迭代器(Iterator):遍历集合的统一方式

所有 Collection 的实现类都支持通过 Iterator 遍历元素,避免暴露底层结构:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        
        // 获取迭代器
        Iterator<String> it = list.iterator();
        // 遍历
        while (it.hasNext()) { // 判断是否有下一个元素
            String s = it.next(); // 获取下一个元素
            System.out.println(s);
        }
    }
}
 

注意:遍历过程中若要删除元素,必须用迭代器的 remove() 方法,否则会抛出 ConcurrentModificationException(快速失败机制)。

2. Collections 工具类:集合操作的 “辅助工具”

java.util.Collections 提供了大量静态方法,简化集合操作:

  • sort():排序(如 Collections.sort(list));
  • reverse():反转元素顺序;
  • shuffle():随机打乱元素;
  • synchronizedList():将非线程安全的集合转为线程安全(如 Collections.synchronizedList(new ArrayList<>()))。

五、如何选择合适的集合?

记住核心场景,按 “需求” 选工具:

需求场景推荐集合
有序可重复,频繁查询 ArrayList
有序可重复,频繁增删中间元素 LinkedList
无序不可重复,追求效率 HashSet
去重且需要排序 TreeSet
键值对存储,无序,追求效率 HashMap
键值对存储,需要按键排序 TreeMap
先进先出(排队) LinkedList(作为 Queue)
按优先级处理元素 PriorityQueue

六、避坑指南

  1. 集合与数组的区别
    数组长度固定,集合长度动态可变;数组可存储基本类型(如 int[]),集合只能存储对象(基本类型需装箱为 Integer 等)。
  2. 线程安全性
    常用集合(ArrayListHashMapHashSet)均为非线程安全,多线程环境下需使用 ConcurrentHashMap(线程安全的 Map)、CopyOnWriteArrayList(线程安全的 List)等。
  3. 自定义对象作为键 / 元素
    存储自定义对象到 HashSet 或作为 HashMap 的键时,必须重写 hashCode() 和 equals() 方法,否则无法正确去重或查询

posted on 2025-09-03 08:44  coding博客  阅读(51)  评论(0)    收藏  举报