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的教学内容!!!

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

相关推荐
m0_715575344 小时前
分布式任务调度系统
开发语言·c++·算法
Configure-Handler4 小时前
buildroot System configuration
java·服务器·数据库
csbysj20204 小时前
选择(Selectable)
开发语言
naruto_lnq4 小时前
泛型编程与STL设计思想
开发语言·c++·算法
:Concerto4 小时前
JavaSE 注解
java·开发语言·sprint
m0_748708055 小时前
C++中的观察者模式实战
开发语言·c++·算法
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.5 小时前
Keepalived VIP迁移邮件告警配置指南
运维·服务器·笔记
电商API_180079052475 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫
qq_537562675 小时前
跨语言调用C++接口
开发语言·c++·算法
wjs20245 小时前
DOM CDATA
开发语言