Java基础——集合进阶3

一、ArrayList

1.1 什么是 ArrayList?

ArrayList 是 Java 集合框架中 List 接口的一个 基于动态数组实现的可变长列表

✅ 核心定义:

  • 实现了 ListRandomAccess(支持快速随机访问)、CloneableSerializable 接口
  • 底层使用 Object[] 数组存储元素
  • 线程不安全(非同步)
  • 允许存储 null 值,且允许多个 null

自然Collection和List的所有方法实现类ArrayList也可以用。

1.2 ArrayList 的作用与适用场景

主要作用:

  • 提供一个长度可自动增长的有序容器,用于存储和操作一组对象
  • 支持通过索引快速访问、修改、插入、删除元素

✅ 适用场景(高频使用):

  • 需要频繁通过索引访问元素(如 get(i)
  • 元素数量大致已知或变化不大
  • 主要操作是遍历、读取、末尾添加
  • 不需要线程安全(单线程环境)

💡 "90% 的 List 场景,首选 ArrayList!"

1.3 常用方法与代码示例

方法 说明 时间复杂度
add(E e) 在末尾添加元素 O(1)(均摊)
add(int index, E e) 在指定位置插入 O(n)(需移动后续元素)
get(int index) 获取指定索引元素 O(1)
set(int index, E e) 替换指定位置元素 O(1)
remove(int index) 删除指定索引元素 O(n)
remove(Object o) 删除第一个匹配的元素 O(n)
size() 返回元素个数 O(1)
isEmpty() 是否为空 O(1)
contains(Object o) 是否包含某元素 O(n)
indexOf(Object o) 返回首次出现的索引 O(n)
clear() 清空所有元素 O(1)(仅置 null,不释放数组)
java 复制代码
import java.util.*;

public class ArrayListDemo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        // 添加
        list.add("Apple");
        list.add("Banana");
        list.add(1, "Cherry"); // 插入到索引1

        // 访问
        System.out.println(list.get(0)); // Apple
        System.out.println(list.size()); // 3

        // 修改
        list.set(0, "Apricot");

        // 删除
        list.remove("Banana"); // 删除值
        list.remove(1);        // 删除索引1

        // 遍历
        list.forEach(System.out::println);
    }
}

1.4 ArrayList集合的底层原理

1.1.1 扩容机制

addAll()方法:可以一次添加List1整个集合中的内容全都添加到List2中。考虑源码的时候要把一次添加一个元素的情况和一次全部添加的情况都要考虑。

注意:底层创建出数组是在添加第一个元素的时候创建的,不是事先创建的。

size的两层含义:表示元素个数、下次存入的位置。

具体的流程详解:

首先在底层,通过空参构造来创建了一个集合,默认初始化长度为0,添加第一个元素"aaa";此时调用add()方法;

把参数"aaa"传递过去,底层又帮我们调用一个add()方法,其中就有三个参数。

参数一:当前要添加的元素;

参数二:集合底层数组的名字;

参数三:集合的长度/当前元素应该存入的位置。

那么调用的add()方法,把三个参数传递给了我们的形参,这个add()方法当中首先会做一个判断,s即你当前要添加的位置,s == elementData.length 是不是等于当前数组的长度,如果是调用grow()方法,grow()其实就是数组的扩容。

grow()方法:会把现有的个数+1(size+1); 然后再去调用有参的构造方法,此时数组长度就变成了1,传递给grow()方法体时,形参(minCapacity)就等于1。

int oidCapacity = elementData.length 记录原来的旧有容量(即0),那么接下来的判断就不满足走else语句,那么后面还要扩容的话就执行if语句里面的代码

调用了Math.max()比较DEFAULT_CAPACITY (10)与 minminCapacity(1)水大;所以new object默认就是10,层层进行返回,默认数组长度就是10,在传入参数之后才创建。

💡 为什么是 1.5 倍?

  • 避免频繁扩容(空间换时间)
  • 比 2 倍更节省内存(减少内存碎片)

1.5 高频面试题(面经精要)

Q1:ArrayList 的默认初始容量是多少?

:JDK 8+ 中,空参构造器创建的 ArrayList 初始容量为 0 ,第一次 add 时扩容为 10

(注意:不是一开始就分配 10!)


Q2:ArrayList 如何扩容?扩容多少?

:当元素数量超过当前数组长度时,会创建一个 1.5 倍原容量的新数组,并将旧数组元素复制过去。若 1.5 倍仍不足,则直接扩到所需大小。


Q3:为什么 ArrayList 查询快、增删慢?

  • 查询快:底层是数组,支持 O(1) 随机访问
  • 增删慢:插入或删除中间元素时,需调用 System.arraycopy() 移动后续所有元素,时间复杂度 O(n)

声明:

分析借鉴于通义AI

以上均来源于B站@ITheima的教学内容!!!

本人跟着视频内容学习,整理知识引用

相关推荐
蓝-萧2 小时前
使用Docker构建Node.js应用的详细指南
java·后端
多喝开水少熬夜2 小时前
Trie树相关算法题java实现
java·开发语言·算法
QT 小鲜肉2 小时前
【QT/C++】Qt定时器QTimer类的实现方法详解(超详细)
开发语言·数据库·c++·笔记·qt·学习
MeowKnight9582 小时前
【Qt】Qt实践记录3——UDP通信
笔记·qt
REDcker2 小时前
前端打包工具 - Rollup 打包工具笔记
前端·笔记
lsx2024062 小时前
MySQL WHERE 子句详解
开发语言
Tony Bai2 小时前
【Go模块构建与依赖管理】09 企业级实践:私有仓库与私有 Proxy
开发语言·后端·golang
lkbhua莱克瓦243 小时前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
Lucky小小吴3 小时前
开源项目5——Go版本快速管理工具
开发语言·golang·开源