Java集合框架核心进阶|List/Set/Map/Queue、迭代器、Comparable与Comparator

集合框架真正重要的不只是会用 API,而是知道不同容器在底层结构、去重规则、排序方式和遍历删除上的行为差异。

Java集合框架是日常开发使用率最高、面试必考、工程核心的知识点。相比于固定长度、功能单一的数组,集合可动态扩容、支持海量数据操作、内置丰富增删改查、排序、去重、队列特性,是存储业务数据、实现业务逻辑的核心容器。

本文全覆盖核心考点:List(ArrayList/LinkedList)、Set(HashSet/TreeSet)、Map(HashMap/TreeMap)、Queue队列、迭代器Iterator、Comparable与Comparator比较器,搭配底层原理、完整实战代码、性能对比、高频坑点、工程规范、面试标准答案。

一、Java集合整体体系概述

Java集合分为两大顶层根接口,所有集合实现类均基于以下体系拓展,也是面试底层认知基础:

1.1 两大核心根体系

  • Collection(单列集合):存储单个元素,包含三大子接口

    • List:有序、可重复、有索引

    • Set:无序、不可重复、无索引

    • Queue:队列集合,先进先出、阻塞队列特性

  • Map(双列集合):存储键值对(Key-Value),Key唯一、Value可重复

1.2 常用实现类速览(工程高频)

  • List:ArrayList、LinkedList

  • Set:HashSet、TreeSet

  • Map:HashMap、TreeMap

  • Queue:LinkedList、ArrayDeque、BlockingQueue

二、List 有序可重复集合

List特性:元素有序(存入顺序与取出顺序一致)、可重复、自带索引、支持根据下标精准操作元素。核心两大实现类:ArrayList、LinkedList

2.1 ArrayList(数组实现)

2.1.1 底层原理

底层基于动态扩容数组实现,默认初始化容量10,扩容机制:原容量1.5倍扩容,每次扩容需要数组拷贝。

2.1.2 核心优缺点

  • 优点:支持下标随机访问,查询速度极快,遍历效率高

  • 缺点:中间/头部增删元素需要移动数组元素,增删效率低,扩容产生性能损耗

2.1.3 基础实战代码

import java.util.ArrayList;

public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建集合
        ArrayList<String> list = new ArrayList<>();
        // 添加元素
        list.add("Java");
        list.add("MySQL");
        list.add("Java"); // 允许重复元素

        // 遍历、查询
        System.out.println("根据下标取值:" + list.get(0));
        System.out.println("集合所有元素:" + list);

        // 删除、修改
        list.remove(1);
        list.set(0, "Java进阶");
        System.out.println("操作后元素:" + list);
    }
}

2.2 LinkedList(双向链表实现)

2.2.1 底层原理

底层基于双向链表实现,每个节点存储前驱、后继指针和数据,无需连续内存,不支持扩容,按需创建节点。

2.2.2 核心优缺点

  • 优点:首尾增删元素无需移动数据,增删效率极高,无扩容损耗

  • 缺点:无下标随机访问,查询需要遍历链表,查询效率低

2.2.3 基础实战代码

import java.util.LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(10);
        list.add(20);

        // 首尾快速操作(LinkedList专属优势)
        list.addFirst(5);
        list.addLast(30);
        System.out.println("首尾操作后:" + list);

        list.removeFirst();
        list.removeLast();
        System.out.println("删除首尾后:" + list);
    }
}

2.3 ArrayList vs LinkedList 面试终极对比

对比维度 ArrayList LinkedList
底层结构 动态数组 双向链表
查询效率 快(随机访问O(1)) 慢(遍历查询O(n))
增删效率 慢(需移动元素、扩容) 快(仅修改指针)
内存占用 连续内存,利用率高 节点存指针,内存冗余大
使用场景 查询多、遍历多、增删少 首尾频繁增删、队列场景

三、Set 无序去重集合

Set特性:元素无序、不可重复、无索引,核心用于数据去重、自动排序场景,主流实现:HashSet、TreeSet。

3.1 HashSet(哈希去重)

3.1.1 底层原理

底层基于 HashMap 实现,利用哈希算法去重,通过 hashCode\(\) \+ equals\(\) 双重校验判断元素是否重复。

3.1.2 去重规则(面试必考)

  1. 先调用 hashCode\(\) 获取哈希值,哈希值不同:直接判定不重复,存入集合

  2. 哈希值相同:再调用 equals\(\) 比较内容,返回true判定重复,拒绝存入

核心坑点:自定义对象存入HashSet,必须重写hashCode和equals方法,否则无法去重!

3.1.3 实战代码(自定义对象去重)

import java.util.HashSet;
import java.util.Objects;

// 自定义实体类,必须重写hashCode+equals
class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    // 重写:根据业务字段判断重复
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(name, user.name) && Objects.equals(age, user.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

public class HashSetDemo {
    public static void main(String[] args) {
        HashSet<User> set = new HashSet<>();
        set.add(new User("张三", 20));
        set.add(new User("张三", 20)); // 重复元素,自动去重
        set.add(new User("李四", 22));

        System.out.println("去重后集合:" + set);
    }
}

3.2 TreeSet(有序去重)

3.2.1 底层原理

底层基于 TreeMap 红黑树实现,自动升序排序+去重,支持自然排序、自定义比较器排序。

3.2.2 核心特性

  • 默认对数值、字符串自然排序

  • 自定义对象必须指定排序规则(Comparable/Comparator),否则直接报错

  • 有序、去重、查询效率稳定

3.2.3 基础排序实战

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        // 自动自然升序排序+去重
        TreeSet<Integer> set = new TreeSet<>();
        set.add(5);
        set.add(2);
        set.add(9);
        set.add(2); // 重复自动去除

        // 输出有序结果:[2,5,9]
        System.out.println("TreeSet排序结果:" + set);
    }
}

四、Map 键值对集合

Map特性:双列键值对存储,Key唯一不可重复、Value可重复,Key重复会覆盖原有Value,是业务数据映射、缓存存储核心容器。

4.1 HashMap(无序键值对)

4.1.1 底层核心原理(JDK1.8 面试重中之重)

底层结构:数组 + 链表 + 红黑树,解决哈希冲突,兼顾查询与增删效率

  • 默认容量16,负载因子0.75,扩容阈值12,扩容2倍

  • 链表长度&gt;8 且 数组长度&gt;64:链表转为红黑树

  • 红黑树节点数&lt;6:退化为链表

4.1.2 核心特性

无序存储、查询速度极快、允许null键null值(仅一个null key)、线程不安全。

4.1.3 遍历实战(三种主流方式)

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class HashMapDemo {
    public static void main(String[] args) {
        HashMap<String, Integer> map = new HashMap<>();
        map.put("Java", 100);
        map.put("MySQL", 90);
        map.put("Java", 99); // key重复,覆盖value

        // 方式1:遍历key
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key + "=" + map.get(key));
        }

        // 方式2:遍历键值对(推荐,效率最高)
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }
}

4.2 TreeMap(有序键值对)

4.2.1 底层原理

底层基于红黑树实现,默认根据Key自然升序排序,支持自定义排序规则,Key不可为null。

4.2.2 核心特性

  • Key自动排序、唯一去重

  • 有序存储,适合排序映射场景

  • 增删查效率稳定,略低于HashMap

五、Queue 队列集合

Queue队列特性:遵循FIFO先进先出规则,多用于任务队列、消息队列、限流排队、线程池任务存储。

5.1 常用队列实现类

  • LinkedList:普通非阻塞队列,基于链表实现

  • ArrayDeque:数组双端队列,效率高于LinkedList,推荐优先使用

  • BlockingQueue:阻塞队列,多线程并发核心,满阻塞、空阻塞

5.2 队列基础实战

import java.util.Queue;
import java.util.ArrayDeque;

public class QueueDemo {
    public static void main(String[] args) {
        Queue<String> queue = new ArrayDeque<>();
        // 入队
        queue.offer("任务1");
        queue.offer("任务2");
        queue.offer("任务3");

        // 出队(先进先出)
        while (!queue.isEmpty()) {
            System.out.println("执行:" + queue.poll());
        }
    }
}

六、迭代器 Iterator(集合通用遍历)

Iterator是所有单列集合的通用遍历方式,也是集合底层遍历原理,解决普通for循环遍历删除元素的并发修改异常问题。

6.1 核心方法

  • hasNext\(\):判断是否有下一个元素

  • next\(\):获取下一个元素

  • remove\(\):安全删除当前遍历元素

6.2 迭代器安全删除实战(解决并发修改异常)

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

public class IteratorDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("张三");
        list.add("李四");
        list.add("王五");

        // 迭代器安全遍历删除
        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            String name = it.next();
            if ("李四".equals(name)) {
                it.remove(); // 迭代器自带删除,无并发异常
            }
        }
        System.out.println(list);
    }
}

6.3 高频坑点:并发修改异常

问题场景:增强for循环/普通for循环遍历集合时,直接调用集合remove()删除元素,触发 ConcurrentModificationException

解决方案:遍历删除元素必须使用 迭代器remove() 或 JDK8 removeIf。

七、比较器:Comparable vs Comparator(排序核心)

Java集合排序仅有两种方式:自然排序Comparable、自定义排序Comparator,是TreeSet/TreeMap/集合工具类排序的底层核心,面试高频对比考点。

7.1 Comparable(内部自然排序)

特点:实体类内部实现接口,定义默认排序规则,属于侵入式排序

实战代码

// 实体类实现Comparable,重写默认排序规则
class Student implements Comparable<Student>{
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    // 自然排序:年龄升序
    @Override
    public int compareTo(Student s) {
        return this.age - s.age;
    }

    @Override
    public String toString() {
        return name + "-" + age;
    }
}

7.2 Comparator(外部比较器自定义排序)

特点外部定义排序规则,不修改实体类源码,非侵入式,灵活适配多场景排序,工程开发首选。

实战代码(Lambda简化写法)

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class ComparatorDemo {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("张三", 20));
        list.add(new Student("李四", 18));
        list.add(new Student("王五", 22));

        // 外部自定义排序:年龄降序(灵活修改,不改动实体类)
        Collections.sort(list, (s1, s2) -> s2.getAge() - s1.getAge());
        System.out.println("自定义排序:" + list);
    }
}

7.3 两大比较器终极面试对比

对比维度 Comparable(内部比较器) Comparator(外部比较器)
位置 实体类内部实现 外部单独定义
侵入性 侵入源码,修改需改实体类 无侵入,不改动原有代码
排序规则 固定默认排序 灵活多变,支持多场景排序
使用场景 全局统一默认排序 临时排序、多规则差异化排序

八、集合工程最佳实践 &amp; 避坑指南

  • 优先使用ArrayList:90%业务场景查询遍历居多,性能最优

  • HashMap初始化容量:预估数据量,避免频繁扩容(初始容量=数据量/0.75+1)

  • 自定义对象存Set/Map:必须重写hashCode+equals,否则去重失效

  • 遍历删除元素:禁止普通for/增强for删除,使用迭代器或removeIf

  • 排序优先Comparator:外部排序解耦,符合开闭原则

  • 线程安全:普通集合线程不安全,并发场景使用ConcurrentHashMap、CopyOnWriteArrayList

九、全文核心总结(面试必背)

  • List:有序可重复有索引,ArrayList查快增删慢,LinkedList首尾增删快

  • Set:无序不可重复无索引,HashSet哈希去重,TreeSet有序排序去重

  • Map:键值对存储,HashMap无序高效,TreeMap按键有序排序

  • Queue:先进先出队列,适合任务排队、消息队列场景

  • 迭代器:集合通用遍历,唯一安全遍历删除方式,解决并发修改异常

  • 比较器:Comparable内部默认排序,Comparator外部灵活自定义排序,工程优先用后者

十、高频面试简答题

  • ArrayList和LinkedList区别? 基于数组和双向链表实现,ArrayList查询快增删慢,LinkedList首尾增删快查询慢。

  • HashSet去重原理? 重写hashCode+equals,先比哈希值、再比内容,双重校验去重。

  • HashMap底层结构? JDK1.8采用数组+链表+红黑树,链表过长树化,优化查询性能。

  • 为什么遍历删除会报并发修改异常? 增强for循环基于迭代器实现,遍历中修改集合长度会触发修改次数校验失败。

  • Comparable和Comparator区别? 前者内部侵入式默认排序,后者外部非侵入式灵活排序,业务开发优先使用Comparator。

  • TreeSet为什么能排序去重? 底层红黑树,基于比较器规则判断大小与重复,自动排序去重。

  • ArrayDeque和LinkedList队列区别? ArrayDeque基于数组,效率更高、无指针冗余,优先作为队列使用。

本文总结

  • List、Set、Map、Queue 的差异不能只停留在有序无序、可重复不可重复,还要落到底层结构与典型业务场景。
  • HashMap、HashSet、TreeSet、TreeMap 这些容器的性能和行为,本质上由数组、链表、哈希和红黑树这些底层结构决定。
  • 迭代器安全删除、Comparable 默认排序和 Comparator 外部排序,是集合题里最常见也最容易答浅的三个高频点。
GYSTACK 文章文末广告 硅云云服务器活动 适合个人项目、轻量建站和出海业务部署。
后浪云移动端信息流广告 后浪云主机服务 适合长期部署、独立站和海外机房需求。