Skip to content

2026-08-29 · List:有序可重复;Set:去重。日常用 ArrayList + HashSet 就覆盖 90% 场景。

Java List 与 Set 集合

1. List 接口:有序、可重复

List 的两个特点:

  • 有序:按添加顺序排列(下标从 0 开始)
  • 可重复:同一个元素可以存多份
java
List<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("张三");   // ✅ 允许重复

System.out.println(list); // [张三, 李四, 张三]
System.out.println(list.get(1)); // 李四(按下标取)

List 特有方法(全靠下标):

方法作用
get(index)按下标取元素
set(index, 元素)修改指定位置的元素
indexOf(元素)查找元素第一次出现的位置,找不到返回 -1
remove(index)按下标删除
subList(0, 2)截取子列表

2. ArrayList:底层是数组(最常用)

java
List<String> list = new ArrayList<>();          // 默认容量 10
List<String> list2 = new ArrayList<>(100);      // 提前指定容量(要存很多就指定)

list.add("a");
list.add("b");
list.remove(0);            // 按下标删
list.remove("b");          // 按元素删(第一个匹配的)
list.get(0);               // 按下标查
list.contains("a");        // 是否包含
list.size();               // 长度(不是 length,是方法)

为什么"查快、增删慢"

  • 底层是数组(连续内存),按下标查直接算地址,O(1) 极快
  • 中间插入/删除,后面所有元素都要往后/往前挪一位,O(n) 慢

扩容机制:默认容量 10,装满了扩容为原来的 1.5 倍,把旧数据拷进新数组。扩容要整体拷贝,所以预知要存大量数据时直接 new ArrayList<>(容量)

3. LinkedList:底层是链表(了解即可)

每个节点存自己的值 + 下一个节点的地址,链式相连:

[a] → [b] → [c] → null
  • 增删快:中间插入只改两个节点的"箭头",O(1)
  • 查得慢:没有下标,要找第 5 个必须从头走过去,O(n)

实际开发 90% 用 ArrayList。LinkedList 的"增删快"只在中间频繁插入删除的场景才成立,绝大多数业务是"末尾追加 + 按条件查",ArrayList 更合适。

4. Set 接口:去重

Set 的特点:不重复——加重复元素会被拒绝;无下标——不能 get(i)

java
Set<String> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("a");       // ❌ 重复,加不进去

System.out.println(set); // [a, b](只有一个 a)

// Set 没有 get(index),遍历用增强 for
for (String s : set) {
    System.out.println(s);
}

Set 靠 equals 判断重复——去重就是"先算 hashCode 定位,再看 equals 是否相等,相等就拒绝"。

5. HashSet(去重主力)

java
Set<String> set = new HashSet<>();  // 底层哈希表,查重 O(1),极快
set.add("a");
set.add("b");

特点

  • 无序(遍历顺序不稳定,跟哈希值有关)
  • 查重极快(不用遍历全部,直接算哈希定位)

⚠️ 坑:自定义对象必须重写 equals + hashCode

对 String、Integer 这类 JDK 自带类,去重自动生效。但自定义类不重写这两个方法,去重失效

java
class Student {
    String name;
    int age;
    // 没重写 equals/hashCode → 每个 new 出来的都是"不同的对象"
}

Set<Student> set = new HashSet<>();
set.add(new Student("张三", 20));
set.add(new Student("张三", 20));  // ❌ 加进去了!两个都进

IDEA 快捷键 Alt+Insert → equals() and hashCode(),自动生成,别手写。

规矩:重写 equals 必须同时重写 hashCode

6. LinkedHashSet:去重 + 保插入顺序

java
Set<String> set = new LinkedHashSet<>();
set.add("c");
set.add("a");
set.add("b");

System.out.println(set); // [c, a, b](按添加顺序)

场景:去重一批用户,且要保持原来的顺序 → LinkedHashSet。

7. TreeSet:去重 + 自动排序(了解即可)

元素放进去自动升序排列:

java
Set<Integer> set = new TreeSet<>();
set.add(5);
set.add(1);
set.add(3);
System.out.println(set); // [1, 3, 5]

底层是红黑树(自平衡二叉树),元素自动排序但性能最慢。自定义对象排序要实现 Comparable 接口,或用构造传 Comparator(Lambda):

java
Set<Student> set = new TreeSet<>((s1, s2) -> s1.age - s2.age); // 按年龄排序

业务里"要排序的集合"大部分直接用 SQL 的 ORDER BY 或 Stream 的 sorted() 解决,TreeSet 用得少,知道有这功能即可。

8. 选型小结

场景选哪个
存一批数据按顺序取ArrayList(默认)
去重HashSet
去重 + 保顺序LinkedHashSet
去重 + 排序TreeSet(少用,排序交给 SQL/Stream)