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

深入解析 ArrayList

一、线性表与顺序表基础

线性表是数据元素的有限序列,逻辑上连续(如排队),物理存储可连续(数组)或不连续(链表)。常见类型:

  • 顺序表(数组实现)
  • 链表(指针连接)
  • 栈/队列(受限线性表)

顺序表是用连续内存空间存储元素的线性结构,核心特点:

// 顺序表伪代码结构
class SeqList {private int[] array;  // 连续存储空间private int size;     // 有效元素个数void add(int data) { /* 尾部插入 */ }void remove(int index) { /* 删除需移动后续元素 */ }
}
二、ArrayList 核心特性

作为动态顺序表实现,核心特点:

  1. 动态扩容:容量不足时自动扩容(默认10→15→22...)
  2. 快速随机访问:实现 RandomAccess 接口
  3. 泛型支持ArrayList<String> 类型安全
  4. 非线程安全:多线程需用 Vector 或同步包装
三、ArrayList 使用详解
1. 构造方法
// 示例1:默认构造(初始容量10)
List<Integer> list1 = new ArrayList<>();// 示例2:指定初始容量
List<String> list2 = new ArrayList<>(100); // 示例3:从已有集合构造
List<Integer> list3 = new ArrayList<>(Arrays.asList(1,2,3));
2. 核心操作(附时间复杂度)
方法功能时间复杂度示例
add(E e)尾部插入O(1)list.add("Java")
add(index, E)指定位置插入O(n)list.add(0, "First")
get(index)获取元素O(1)String s = list.get(0)
set(index, E)修改元素O(1)list.set(1, "Python")
remove(index)按索引删除O(n)list.remove(0)
remove(Object)按元素删除O(n)list.remove("Java")
contains(Object)是否包含O(n)if(list.contains("C++"))
subList(from, to)获取子列表O(1)List sub = list.subList(1,3)

 注意:subList() 返回视图,修改会影响原列表!

 3. 三种遍历方式

List<String> langs = Arrays.asList("Java", "Python", "C++");// 方式1:for+索引(最快)
for(int i=0; i<langs.size(); i++) {System.out.println(langs.get(i));
}// 方式2:foreach
for(String lang : langs) {System.out.println(lang);
}// 方式3:迭代器(统一集合访问)
Iterator<String> it = langs.iterator();
while(it.hasNext()) {System.out.println(it.next());
}
四、动态扩容机制(源码级解析)

扩容触发条件:添加元素时 size + 1 > capacity

// 简化版扩容流程
public boolean add(E e) {ensureCapacityInternal(size + 1); // 1. 检查容量elementData[size++] = e;          // 2. 添加元素return true;
}private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(10, minCapacity); // 首次扩容到10}if (minCapacity > elementData.length) {grow(minCapacity); // 需要扩容}
}private void grow(int minCapacity) {int oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1); // 1.5倍扩容if (newCapacity < minCapacity) {newCapacity = minCapacity; // 特殊需求扩容}elementData = Arrays.copyOf(elementData, newCapacity); // 数据拷贝
}

扩容规律

  • 初始容量:10
  • 第一次扩容:10 → 15(10 + 10/2)
  • 第二次扩容:15 → 22(15 + 15/2)
  • 最大容量:Integer.MAX_VALUE - 8
五、实战案例:扑克牌游戏
1. 扑克牌类设计
class Card {public int rank;     // 牌面值public String suit;  // 花色@Overridepublic String toString() {return "[" + suit + " " + rank + "]";}
}
2. 洗牌算法实现
public class CardGame {private static final String[] SUITS = {"♠", "♥", "♣", "♦"};// 创建一副牌private static List<Card> buyDeck() {List<Card> deck = new ArrayList<>(52);for (int i = 0; i < 4; i++) {for (int j = 1; j <= 13; j++) {Card card = new Card();card.suit = SUITS[i];card.rank = j;deck.add(card);}}return deck;}// 洗牌(Fisher-Yates算法)private static void shuffle(List<Card> deck) {Random random = new Random();for (int i = deck.size() - 1; i > 0; i--) {int j = random.nextInt(i + 1);// 交换两张牌Card temp = deck.get(i);deck.set(i, deck.get(j));deck.set(j, temp);}}public static void main(String[] args) {List<Card> deck = buyDeck();System.out.println("新牌: " + deck);shuffle(deck);System.out.println("洗牌后: " + deck);// 发牌给3个玩家List<List<Card>> players = new ArrayList<>();for(int i=0; i<3; i++) {players.add(new ArrayList<>());}for(int i=0; i<5; i++) {for(int j=0; j<3; j++) {// 从牌堆顶部取牌players.get(j).add(deck.remove(0));}}System.out.println("玩家1手牌: " + players.get(0));System.out.println("玩家2手牌: " + players.get(1));System.out.println("玩家3手牌: " + players.get(2));System.out.println("剩余牌堆: " + deck);}
}
六、ArrayList 的优缺点

优点

  1. 随机访问效率高(O(1)时间复杂度)
  2. 尾部插入效率高(O(1)均摊时间)
  3. 内存连续存储,CPU缓存友好

 缺点

  1. 插入/删除代价高:中间位置操作需移动元素(O(n)时间)

// 在索引2处插入元素
list.add(2, "New");
// 需要移动 [2, size-1] 的所有元素
  1. 内存浪费:扩容后可能有闲置空间

    • 示例:100容量→扩容到150→实际只用105个→浪费45空间
  2. 扩容性能开销:数据拷贝消耗资源

七、使用建议
  1. 预分配容量:已知数据量时指定初始容量

  2. 尾部操作优先:避免中间插入/删除

  3. 替代方案选择

    • 频繁插入删除 → LinkedList
    • 线程安全需求 → CopyOnWriteArrayList
    • 固定大小集合 → Arrays.asList()
http://www.dtcms.com/a/276994.html

相关文章:

  • XGBoost三部曲:XGBoost原理
  • Docker一键安装中间件(RocketMq、Nginx、MySql、Minio、Jenkins、Redis)脚步
  • Transformer 小记(一):深入理解 Transformer 中的位置关系
  • 【PTA数据结构 | C语言版】字符串截取子串操作
  • ABP VNext + 多级缓存架构:本地 + Redis + CDN
  • ref 和 reactive
  • EWSGAN:自动搜索高性能的GAN生成器架构
  • LeetCode 1156.单字符重复子串的最大长度
  • 维基艺术图片: 数据标注 (2)
  • C语言基础教程(002):变量介绍
  • 一文读懂现代卷积神经网络—使用块的网络(VGG)
  • 基于Prompt结构的语校解析:3H日本语学校信息建模实录(4/500)
  • 08.如何正确关闭文件
  • 数智管理学(三十三)
  • 归并排序递归法和非递归法的简单简单介绍
  • Gin框架统一响应与中间件机制学习笔记
  • DH(Denavit–Hartenberg)矩阵
  • KL散度:信息差异的量化标尺 | 从概率分布对齐到模型优化的核心度量
  • 使用QtTest
  • 反激变换器设计全流程(一)——电路拓扑及工作流程
  • Chrome v109.0.5414.168 绿色便携版 Windows 7/2012R2 最终版 下载
  • 开发语言的优劣势对比及主要应用领域分析
  • GROW领导力模型
  • Unity物理系统由浅入深第四节:物理约束求解与稳定性
  • 【算法分析与设计】研究生第一次算法作业latex源码+pdf
  • docker容器高级管理-dockerfile创建镜像
  • 飞算 JavaAI 智能编程助手:颠覆编程旧模式,重构开发生态
  • Java小白-线程 vs 虚拟线程,Java并发的新旧对决
  • LeetCode--44.通配符匹配
  • Java4种设计模式详解(单例模式、工厂模式、适配器模式、代理模式)