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

List 经典问

List(JDK 1.8)

3.1 数组

3.1.1 数组概述

  • 数组定义:连续内存存储相同类型的数据的线性结构。
int[] array = {22, 33, 88, 66, 55, 25};
  • 内存表示
    • 栈内存保存数组变量array,存储数组首地址引用
    • 堆内存保存实际数组元素[22,33,88,66,55,25]

3.1.2 数组寻址公式

访问数组元素:

array[i] = baseAddress + i * dataTypeSize
  • baseAddress:数组首地址
  • i:索引
  • dataTypeSize:元素类型大小(int=4字节)

示例

array[1] = 10 + 1 * 4 = 14

堆中地址 14 处就是array[1]的值 33。


3.1.3 操作时间复杂度

操作时间复杂度说明
随机访问array[i]O(1)直接计算地址
未知索引查找O(n)遍历数组
已排序数组二分查找O(log n)二分查找
插入O(n)插入位置后的元素都要后移
删除O(n)删除位置后的元素都要前移

3.2 ArrayList(JDK 1.8)源码分析

3.2.1 成员变量

private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object[] elementData; // 底层数组 private int size; // 实际元素个数
  • DEFAULT_CAPACITY:默认初始容量 10,用于无参构造第一次 add 扩容
  • EMPTY_ELEMENTDATA:容量为 0 的共享空数组,用于new ArrayList<>(0)
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA:用于无参构造的空数组,第一次 add 扩容到 10
  • elementData:实际存储元素的数组
  • size:当前元素个数

3.2.2 构造方法

// 带初始容量 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } } // 无参构造 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 通过 Collection 构造 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; }
  • 无参构造不会立即开 10 个长度数组,第一次add时才扩容
  • 带容量构造立即分配指定容量数组
  • Collection 构造直接把 collection 转成数组赋值给elementData,共享同一内存地址

3.2.3 添加数据流程 (

add(E e)

源码:

public boolean add(E e) { ensureCapacityInternal(size + 1); // 确保容量 elementData[size++] = e; // 添加元素 return true; }
ensureCapacityInternal(size + 1)
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); }
calculateCapacity
private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); // 无参构造第一次 add 扩到 10 } return minCapacity; // 其他情况直接返回 minCapacity }
ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) { modCount++; if (minCapacity - elementData.length > 0) { grow(minCapacity); // 扩容 } }
grow 方法
private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩 1.5 倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 不够用,直接用 minCapacity if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); // 拷贝旧数组 }
  • 1.5 倍扩容,减少频繁扩容开销
  • Arrays.copyOf复制旧元素到新数组
  • size++后添加新元素

3.2.4 初始容量 & 扩容总结

构造方式初始 elementData.length第一次 add 后容量
new ArrayList<>()0 (DEFAULTCAPACITY_EMPTY_ELEMENTDATA)10
new ArrayList<>(0)0 (EMPTY_ELEMENTDATA)1
new ArrayList<>(10)10不扩容
  • 扩容逻辑:容量不足 → 调grow()→ 新容量 = 旧容量 * 1.5(若不够用,则直接用 minCapacity)

3.2.5 面试题示例

  1. ArrayList list=new ArrayList(10):未添加元素,未扩容
  2. Arrays.asList(array)
    • 修改数组 → List 也变,底层共享同一内存
    • 修改 List 元素 → 数组也变
    • 不能 add/remove,固定长度
  3. list.toArray()
    • 返回数组是拷贝,修改 List 不影响数组,修改数组不影响 List

3.3 总结要点(面试必备)

  1. ArrayList 底层结构:动态数组(Object[])+ size
  2. 无参构造:第一次 add 才开容量 10
  3. 扩容策略:1.5 倍,使用Arrays.copyOf
  4. add(E e) 流程
    1. 计算所需容量 (size + 1) →calculateCapacity
    2. 确认容量 →ensureExplicitCapacity
    3. 扩容 →grow
    4. 添加元素 →elementData[size++] = e
  5. 数组与 List 转换
    • Arrays.asList→ 底层共享数组
    • list.toArray()→ 拷贝数组,不共享
  6. 数组操作复杂度
    • 随机访问 O(1)
    • 遍历查找 O(n)
    • 插入/删除 O(n)

http://www.cnnetsun.cn/news/2766667.html

相关文章:

  • 数据科学三本核心书:统计直觉、工程落地与职业伦理
  • 甲烷水合物生成压力快速计算MATLAB工具:集成vdw-P与RK方程的相平衡求解器
  • 三分钟快速入门:Mootdx通达信数据解析工具的终极指南
  • 【征稿开启】2026年光电、材料、医工高新技术国际学术会议暨第三届人工智能、光电子学与光学技术国际研讨会(AIOT 2026
  • 中兴光猫破解工具zteOnu:5步解锁高级管理权限完整指南
  • 亏损近 2 亿美元、技术或难成功,Quantinuum 上市为何仍受投资者热捧?
  • 全球立式连续封口机市场研究与行业调研
  • 5MB终极解决方案:文泉驿微黑字体如何重塑资源受限环境的中文显示
  • 3PEAK思瑞浦 TP2304-TR TSSOP14 精密运放
  • 广义预测控制MATLAB实战代码包:含系统辨识、多种GPC算法及对比控制器实现
  • 2026年亲测AI写作辅助平台合集(实测甄选版)
  • 6.3万Star的反向代理Traefik,让你彻底告别Nginx手动配路由
  • 保姆级教程:从GPU-Z到HWiNFO,手把手教你排查显卡性能瓶颈和硬件兼容性问题
  • 如何用DouyinLiveRecorder轻松实现40+平台直播永久录制:新手终极指南
  • N皇后问题的遗传算法Python实操:从编码到调参全解析
  • 别再手动点Next了!Quartus Prime 15.0 新建工程的保姆级配置清单(附Modelsim避坑指南)
  • 2026抖音SEO系统培训全解,吃透搜索流量轻松稳定获客变现
  • Windows远程桌面多开不求人:用IDA Pro手动分析termsrv.dll,自己生成rdpwrap.ini配置
  • Build 2026 刚讲完 Agent,我反而重看了一遍 MinerU
  • AWVS实战:从‘完全扫描’到结果分析,一次搞定DVWA的78个漏洞
  • QMCDecode:3步解锁QQ音乐加密格式,实现跨平台播放自由终极指南
  • Java 微服务优雅停机:从踩坑到最佳实践
  • 面向工程落地的LLM论文筛选方法论:可复现、低开销、快集成
  • OPC 提问能力的培育方法
  • 别被坑了!2026实测靠谱的AI论文平台|安心版
  • 智慧路灯集中管理与物联网平台架构——从路灯终端到数字孪生运维
  • STM32MP157裸机环境下DHT11温湿度读取工程(HAL库封装,Keil一键编译)
  • 2026视频去水印教程,合法去除视频水印方法全攻略
  • 2026视频去水印方法汇总,详解合法去除视频水印相关规定
  • 从安装到排错:CentOS 7/8下snmpwalk保姆级配置指南(附常见错误解决)