一、集合概述(前置基础)

一、集合概述(前置基础)

集合是Java中用于存储多个数据的容器,区别于数组(固定长度、只能存储同一种基本类型/引用类型),集合长度可变,可存储不同类型的对象(本质存储对象引用),核心接口是Collection,List和Set是Collection的两大核心子接口。

核心特点:集合只存储对象,不存储基本数据类型(需使用包装类,如int→Integer);长度可动态增减;提供了丰富的方法(添加、删除、遍历、查找等),简化数据操作。

Collection核心通用方法(List和Set均适用):

  • add(E e):添加单个元素,返回boolean(添加成功为true);

  • remove(Object o):删除指定元素,返回boolean;

  • size():返回集合中元素的个数;

  • isEmpty():判断集合是否为空;

  • clear():清空集合中所有元素;

  • contains(Object o):判断集合中是否包含指定元素。

二、List集合

1. 核心定义与特点

List是Collection的子接口,代表有序、可重复的集合,元素有明确的索引(类似数组的下标),可通过索引快速访问、插入、删除元素,适合需要"有序存储、可重复、按索引操作"的场景。

核心特点:有序(元素存入顺序与取出顺序一致)、可重复(允许存储多个相同的元素)、有索引(从0开始,依次递增)。

2. List接口的常用实现类(3个核心)

(1)ArrayList(最常用)

底层基于数组实现,查询效率高(通过索引直接访问,时间复杂度O(1)),增删效率低(需移动数组元素,时间复杂度O(n)),线程不安全,效率高,适合"查询频繁、增删较少"的场景(如展示列表数据)。

复制代码
// ArrayList示例
List<String> list = new ArrayList<>();
// 添加元素
list.add("Java");
list.add("Python");
list.add("Java"); // 允许重复
// 按索引插入元素(指定位置插入)
list.add(1, "C++"); // 插入后:[Java, C++, Python, Java]
// 按索引访问元素
String element = list.get(0); // 结果:Java
// 按索引修改元素
list.set(2, "JavaScript"); // 修改后:[Java, C++, JavaScript, Java]
// 按索引删除元素
list.remove(3); // 删除索引3的元素,返回删除的元素
// 遍历集合(三种方式)
// 1. 普通for循环(利用索引,最常用)
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
// 2. 增强for循环(foreach,无需索引)
for (String str : list) {
    System.out.println(str);
}
// 3. 迭代器遍历(安全遍历,可在遍历中删除元素)
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String str = iterator.next();
    if ("C++".equals(str)) {
        iterator.remove(); // 迭代器删除,避免并发修改异常
    }
}

(2)LinkedList

底层基于双向链表实现,查询效率低(需从头/尾遍历查找,时间复杂度O(n)),增删效率高(只需修改链表节点的指针,时间复杂度O(1)),线程不安全,适合"增删频繁、查询较少"的场景(如队列、栈的实现)。

额外特性:LinkedList还实现了Deque接口,可作为队列(先进先出)、栈(先进后出)使用,提供了poll()、push()、pop()等方法。

(3)Vector

底层基于数组实现,与ArrayList功能基本一致,但线程安全(方法加了synchronized锁),效率低,目前已基本被ArrayList替代,仅在多线程场景下偶尔使用。

3. List集合的特有方法(区别于Set)

因List有索引,所以拥有Set没有的、基于索引的操作方法:

  • get(int index):获取指定索引的元素;

  • set(int index, E e):修改指定索引的元素,返回被修改的旧元素;

  • add(int index, E e):在指定索引插入元素,后续元素后移;

  • remove(int index):删除指定索引的元素,返回被删除的元素;

  • indexOf(Object o):返回指定元素在集合中第一次出现的索引,没有则返回-1;

  • lastIndexOf(Object o):返回指定元素在集合中最后一次出现的索引,没有则返回-1。

4. List集合的注意事项

  • ArrayList和LinkedList均线程不安全,多线程环境下需手动加锁,或使用Collections.synchronizedList()包装;

  • 遍历ArrayList时,优先使用普通for循环(效率高);遍历LinkedList时,优先使用增强for或迭代器(避免频繁通过索引查找);

  • 避免在增强for循环中修改集合(添加/删除元素),会抛出ConcurrentModificationException(并发修改异常),需使用迭代器删除。

三、Set集合

1. 核心定义与特点

Set是Collection的子接口,代表无序、不可重复的集合,元素没有索引,无法通过索引访问元素,适合需要"去重存储、无需按顺序访问"的场景(如存储唯一标识、去重数据)。

核心特点:无序(元素存入顺序与取出顺序不一定一致,底层存储无序)、不可重复(不允许存储两个相等的元素,equals()方法判断相等)、无索引(无法通过下标访问)。

补充:Set判断元素是否重复的规则:先通过hashCode()方法判断哈希值,若哈希值不同,则元素不同;若哈希值相同,再通过equals()方法判断,若equals()返回true,则元素重复,不添加;若返回false,则添加。

2. Set接口的常用实现类(3个核心)

(1)HashSet(最常用)

底层基于**哈希表(HashMap)**实现,无序、不可重复,查询和增删效率都很高(时间复杂度O(1)),线程不安全,适合"去重、高效操作"的常规场景。

复制代码
// HashSet示例
Set<String> set = new HashSet<>();
// 添加元素(不可重复,重复元素添加失败)
set.add("Java");
set.add("Python");
set.add("Java"); // 重复元素,添加失败,集合中仍只有1个Java
// 删除元素
set.remove("Python"); // 删除成功返回true,不存在返回false
// 遍历集合(两种方式,无索引,无法用普通for循环)
// 1. 增强for循环
for (String str : set) {
    System.out.println(str); // 输出顺序可能与添加顺序不一致
}
// 2. 迭代器遍历
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
// 判断元素是否存在
boolean hasJava = set.contains("Java"); // 结果:true

(2)LinkedHashSet

底层基于哈希表+双向链表 实现,是HashSet的子类,特点:有序、不可重复(有序指"存入顺序与取出顺序一致"),查询和增删效率略低于HashSet,线程不安全,适合"去重且需要保持插入顺序"的场景。

(3)TreeSet

底层基于红黑树 实现,无序(不保证插入顺序)、不可重复,但会对元素进行自然排序(默认升序),也可自定义排序规则,查询和增删效率中等(时间复杂度O(log n)),线程不安全,适合"去重且需要排序"的场景。

复制代码
// TreeSet示例(自然排序,String类型默认按字典序升序)
Set<String> treeSet = new TreeSet<>();
treeSet.add("Banana");
treeSet.add("Apple");
treeSet.add("Cherry");
// 遍历输出:Apple、Banana、Cherry(自然排序后)
for (String str : treeSet) {
    System.out.println(str);
}
​
// 自定义排序(如整数降序)
Set<Integer> numSet = new TreeSet<>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1; // 降序排序
    }
});
numSet.add(3);
numSet.add(1);
numSet.add(2);
// 遍历输出:3、2、1

3. Set集合的注意事项

  • HashSet、LinkedHashSet、TreeSet均线程不安全,多线程环境下需使用Collections.synchronizedSet()包装;

  • HashSet存储自定义对象时,需重写hashCode()和equals()方法,否则无法实现去重(默认使用Object类的方法,判断地址是否相同);

  • TreeSet存储自定义对象时,需让对象实现Comparable接口(重写compareTo()方法),或创建TreeSet时传入Comparator,否则会抛出ClassCastException(类型转换异常);

  • Set无索引,无法使用普通for循环遍历,只能用增强for、迭代器遍历。

四、List集合与Set集合的核心区别(重点)

对比维度 List集合 Set集合
有序性 有序(存入与取出顺序一致) 无序(HashSet、TreeSet);LinkedHashSet有序
可重复性 可重复 不可重复
索引 有索引,可通过索引操作 无索引,无法通过索引操作
底层实现 ArrayList(数组)、LinkedList(链表) HashSet(哈希表)、TreeSet(红黑树)
适用场景 需有序、可重复、按索引操作(如列表展示) 需去重、无需索引(如唯一标识存储)

五、核心总结

  1. List和Set均继承自Collection,拥有Collection的所有通用方法;

  2. List核心:有序、可重复、有索引,重点掌握ArrayList和LinkedList的区别;

  3. Set核心:不可重复、无索引,重点掌握HashSet(常规去重)、TreeSet(排序去重)的使用;

  4. 选型原则:需有序/按索引操作→用List;需去重→用Set;需排序去重→TreeSet;需保持插入顺序去重→LinkedHashSet。

相关推荐
Season4501 小时前
C/C++的类型转换
c语言·开发语言·c++
平安的平安1 小时前
Python大模型Function Calling实战:让AI拥有工具使用能力
开发语言·人工智能·python
xyq20241 小时前
Vue.js 实例
开发语言
源码之家1 小时前
计算机毕业设计:Python中药材数据可视化与智能分析平台 Django框架 中药数据分析 医药数据分析数据分析 可视化 爬虫 (建议收藏)✅
python·深度学习·信息可视化·数据分析·django·课程设计
q_35488851531 小时前
计算机毕业设计:Python中药材天地网数据挖掘与可视化系统 Django框架 中药数据分析 医药数据分析数据分析 可视化 爬虫 (建议收藏)✅
python·数据挖掘·数据分析·django·flask·课程设计
敲代码的瓦龙1 小时前
Android?碎片!!!
java·开发语言·android-studio
froginwe111 小时前
SVG 滤镜:全面解析与高效应用
开发语言
枫叶丹41 小时前
【HarmonyOS 6.0】Data Augmentation Kit端侧问答模型:本地化智能问答的技术演进
开发语言·华为·harmonyos
醉舞经阁半卷书11 小时前
LangGraph详解
开发语言·人工智能·python·深度学习·机器学习·自然语言处理