当前位置: 首页 > news >正文

java学习笔记——集合

一、集合概述

1.1 为什么需要集合?

数组的局限性:

长度固定,不能动态改变

只能存储同一种类型的数据

增删操作不方便

集合的优势:

长度可变,自动扩容

提供丰富的操作方法(增删改查、排序等)

支持多种数据结构(链表、树、哈希表等)

1.2 集合的分类

单列集合(Collection):一次存一个元素

双列集合(Map):一次存一对元素(键值对)

二、Collection接口

Collection 常用方法
import java.util.ArrayList; import java.util.Collection; Collection<String> coll = new ArrayList<>(); // 1. 添加元素 coll.add("张三"); coll.add("李四"); coll.add("王五"); System.out.println(coll); // [张三, 李四, 王五] // 2. 删除元素 coll.remove("李四"); // 删除指定元素 System.out.println(coll); // [张三, 王五] // 3. 判断 System.out.println(coll.contains("张三")); // true System.out.println(coll.isEmpty()); // false // 4. 获取长度 System.out.println(coll.size()); // 2 // 5. 清空 coll.clear(); System.out.println(coll.isEmpty()); // true // 6. 转数组 coll.add("A"); coll.add("B"); Object[] arr = coll.toArray(); String[] strArr = coll.toArray(new String[0]);

三、迭代器

3.1定义

迭代器是遍历集合的通用工具,不依赖索引。

3.2 基本使用
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; Collection<String> coll = new ArrayList<>(); coll.add("A"); coll.add("B"); coll.add("C"); // 1. 获取迭代器 Iterator<String> it = coll.iterator(); // 2. 遍历 while (it.hasNext()) { // 判断是否有下一个元素 String s = it.next(); // 获取下一个元素 System.out.println(s); }
3.3 迭代过程原理

3.4 迭代中删除元素
// 使用迭代器的 remove() 方法,不能用集合的 remove() Iterator<String> it = coll.iterator(); while (it.hasNext()) { String s = it.next(); if ("B".equals(s)) { it.remove(); // 正确!用迭代器的remove // coll.remove("B"); // 错误!会抛出ConcurrentModificationException } }
3.5 迭代器源码分析
// ArrayList 内部类 Itr 简化版 private class Itr implements Iterator<E> { int cursor; // 下一个要返回元素的索引 int expectedModCount = modCount; // 期望的修改次数 public boolean hasNext() { return cursor != size; // cursor不等于size说明还有元素 } public E next() { checkForComodification(); // 检查并发修改 int i = cursor; E element = elementData[i]; cursor = i + 1; return element; } // 检查是否在迭代中使用了集合的增删方法 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }

ps:

为什么集合的remove会报错?

集合有个 modCount 记录修改次数

迭代器记录 expectedModCount

集合的remove会修改 modCount,导致两者不一致 → 抛异常

迭代器的remove会同步更新两者,所以安全

四、数据结构基础

4.1 常见数据结构

4.2 数组 vs 链表

数组

链表

五、ArrayList集合

5.1 基本使用
import java.util.ArrayList; ArrayList<String> list = new ArrayList<>(); // 增 list.add("张三"); list.add("李四"); list.add(1, "王五"); // 在索引1处插入 System.out.println(list); // [张三, 王五, 李四] // 删 list.remove(1); // 按索引删除 list.remove("李四"); // 按元素删除 // 改 list.set(0, "张三丰"); // 修改指定索引的元素 // 查 String s = list.get(0); // 按索引查询 int index = list.indexOf("张三丰"); // 查找元素索引 boolean has = list.contains("张三丰"); // 是否包含
5.2 遍历方式
ArrayList<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); // 方式1:普通for循环 for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } // 方式2:增强for循环 for (String s : list) { System.out.println(s); } // 方式3:迭代器 Iterator<String> it = list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } // 方式4:forEach(JDK8+) list.forEach(s -> System.out.println(s));
5.3 ArrayList源码分析
// ArrayList 底层是 Object[] 数组 public class ArrayList<E> { private Object[] elementData; // 存储元素的数组 private int size; // 实际元素个数 // 空参构造:初始为空数组 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // {} } // add 方法 public boolean add(E e) { ensureCapacityInternal(size + 1); // 检查容量,不够就扩容 elementData[size++] = e; // 添加元素,size+1 return true; } // 扩容机制 private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容 elementData = Arrays.copyOf(elementData, newCapacity); } }

核心要点:

底层结构:Object[] 数组

初始容量:JDK7+ 空参构造初始为空数组,第一次add时扩容为10

扩容机制:每次扩容为原来的 1.5倍

查询快O(1):通过索引直接定位

增删慢O(n):需要移动元素

六、LinkedList集合

6.1 基本使用
import java.util.LinkedList; LinkedList<String> list = new LinkedList<>(); // 基本操作同ArrayList list.add("A"); list.add("B"); list.addFirst("开头"); // 头部添加(LinkedList特有) list.addLast("结尾"); // 尾部添加(LinkedList特有) // 获取 String first = list.getFirst(); String last = list.getLast(); // 删除 list.removeFirst(); list.removeLast(); // 模拟栈和队列 list.push("入栈"); // 压栈 String pop = list.pop(); // 弹栈 list.offer("入队"); // 入队 String poll = list.poll(); // 出队
6.2 LinkedList特有方法

6.3 LinkedList源码分析
// LinkedList 底层是双向链表 public class LinkedList<E> { private Node<E> first; // 头节点 private Node<E> last; // 尾节点 private int size; // 元素个数 // 内部类:链表节点 private static class Node<E> { E item; // 存储的数据 Node<E> next; // 下一个节点 Node<E> prev; // 上一个节点 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } } // add方法(尾部添加) public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { Node<E> l = last; Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; } }

核心要点:

底层结构:双向链表

查询慢O(n):需要从头/尾遍历

增删快O(1):只需修改前后节点的指针

实现了 Deque 接口,可以当栈或队列使用

6.4 ArrayList vs LinkedList

七、增强for循环

7.1 语法
for (元素类型 变量名 : 数组或集合) { // 使用变量名 }
7.2 基本使用
// 遍历数组 int[] arr = {1, 2, 3, 4, 5}; for (int num : arr) { System.out.println(num); } // 遍历集合 ArrayList<String> list = new ArrayList<>(); list.add("A"); list.add("B"); for (String s : list) { System.out.println(s); }
7.3 注意事项
// 增强for不能修改原数组/集合 int[] arr = {1, 2, 3}; for (int num : arr) { num = 100; // 只改了临时变量num,不影响arr } System.out.println(arr[0]); // 1(没变) // 要修改元素,用普通for for (int i = 0; i < arr.length; i++) { arr[i] = 100; // 直接修改数组元素 }
7.4 增强for底层原理

增强for遍历集合时,底层是迭代器

// 增强for for (String s : list) { System.out.println(s); } // 等价于 Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); System.out.println(s); }
http://www.jsqmd.com/news/1090733/

相关文章:

  • 鸿蒙 ArkTS 实战:Mental Math Trainer 从状态建模到交互闭环完整解析
  • 在 AMD 云平台上微调 Gemma 4 做「AI 梦境日志」,我替你把 ROCm 这些坑踩完了(附完整流程)
  • 微博图片批量下载终极指南:高效获取高清原图的完整解决方案
  • 3个常见照片元数据管理问题与ExifToolGui高效解决方案
  • 如何快速掌握开源船舶设计:FREE!ship Plus完整入门指南
  • React Fiber 调度机制与优先级算法
  • CDS API深度解析:企业级气候数据访问架构设计与实战指南
  • 当模型能修漏洞,也能制造攻击:企业安全边界正在消失
  • FocusWriter终极指南:免费开源的全屏专注写作工具完全解析
  • MSPM0 RTC模块深度解析:晶振校准、温度补偿与低功耗设计实战
  • crane 容器镜像同步实战指南 — 跨云跨区域免 Docker 方案
  • 写给Java新手的调试工具与日志分析指南
  • 本体论1:你的知识图谱是死的——从被动存储到主动约束
  • Linux学习笔记4:进程和线程的区别
  • 自动化SOP跟进:提升私域复购率工具常见误区规避
  • 工业级数据采集卡的“内部基建”:从主控MCU到全隔离电源与信号链的硬核拆解
  • 卤水点豆腐和胶体聚沉之间的关系
  • Day9 |删除链表倒数第N个节点 相交链表
  • 技术突破:Python实现QQ音乐API数据解析与资源获取方案
  • DSVW:极简Web漏洞靶场实战指南,从SQL注入到XSS攻防演练
  • 解锁BT下载极速体验:trackerslist项目让你的下载速度飙升300%
  • 【操作系统】经典同步问题:读者-写者 / 哲学家进餐
  • 学习周报 Week 6:目标检测
  • 鸿蒙 ArkTS 实战:Recitation Timer 从状态建模到交互闭环完整解析
  • 2026世界杯AI案例适合写进大学生AI作品集吗
  • OpCore-Simplify:三十分钟完成黑苹果配置的智能化解决方案
  • 从零搭建Selenium自动化测试框架:Python+Pytest实战指南
  • 大模型项目进入生产后,真正难管的不是模型:一套 API 接入与向量检索运行手册
  • MyBatis 与 MyBatis-Plus 面试题汇总——从原理到实战
  • 3DMax新手避坑指南:模型导入、选择与显示的实战解析