Java基础——集合进阶3

一、ArrayList

1.1 什么是 ArrayList?

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

✅ 核心定义:

  • 实现了 List、RandomAccess(支持快速随机访问)、Cloneable、Serializable 接口
  • 底层使用 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 小时前
取集合第一个元素,Java 为什么要写三种写法?
java·windows·python·java21
学长毕设2 小时前
基于SpringBoot的餐厅管理系统-附源码
java·spring boot·后端
沫璃染墨2 小时前
从零入门计算机网络系列(十一):HTTP协议进阶——从重定向原理到GET/POST与Fiddler抓包
linux·服务器·开发语言·网络·c++·tcp/ip·html
刚入门的大一新生2 小时前
Linux-线程互斥
java·开发语言
香芋芋圆3 小时前
iD-editor 详解|OSM官方在线编辑器,基于D3.js的轻量地图编辑器
开发语言·javascript·编辑器
赵小哥要冲啦3 小时前
社区邻里互助小程序从 0 到 1 复盘:需求拆解与信任机制设计
java·小程序·需求分析
xiaogai_gai3 小时前
采购业务退款单同步实战:从钉钉审批流到金蝶云星空付款单
java·数据库·钉钉
箓维3 小时前
TCP Socket的进阶实现
网络·笔记·tcp/ip
二哈赛车手3 小时前
新人笔记---hermes定时功能设计,具体讲解以及可优化点
java·人工智能·笔记·spring·ai·typescript
ZWZhangYu3 小时前
从 Dify 实践理解大模型上下文缓存
java·后端·spring