【面试宝典】ArrayList详解

本文深入剖析了ArrayList,从集合概述、ArrayList的数组特性、源码分析到面试题,详细讲解了ArrayList的构造、添加、移除、遍历等操作,并探讨了其扩容策略、fail-fast机制和迭代器的实现。适合Java开发者巩固ArrayList知识和面试准备。

由于本文篇幅过长,为了方便大家阅读和收藏,特意将本文转成了一份PDF版的文档。

点击 下载 Java学习手册,pdf教程。

1. 集合概述

Java中集合主要分为三大类:

  • List:有顺序,可重复。
  • Set:无顺序,不可重复。
  • Map:无顺序,不可重复。

其中List类集合中,最常用的就是ArrayList。

2. ArrayList概述

ArrayList拆分成两个单词分别是Array+List,Array表示数组,List表示列表。所以也表示了ArrayList的底层使用数组实现的。

传统数组在初始化时必须定义长度,且长度不能更改。

int[] arr1 = new int[10];
// 语法糖定义方式,初始化时按照初始成员确定长度
int[] arr2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

ArrayList是动态数组,初始化时可以不定义长度,在JVM判断ArrayList容量不足时,会自动扩容数组。

ArrayList<Integer> arrayList = new ArrayList<>();

3. 数组特性

ArrayList底层使用数组实现,所以ArrayList具备数组的所有特性。在研究ArrayList之前,必须了解数组在JVM中的底层实现原理。

数组的特性

  • 数组元素必须是同一种数据类型。
  • 数组元素在内存中是连续存储的。
  • 数组元素的随机访问效率特别高,可以实现常量级的随机访问,时间复杂度为O(1)。

由第一个特性可知,数组中每一个元素的占用空间都是一样的。第一个特性结合第二个特性可以得出第三个特性。

 

问题:为什么数组查询的效率比链表高?

一个数组对象在创建时,JVM会给其分配一个基地址。在查询该数组中第 K+1 个元素时,只需要 [ 基地址 + K * 元素大小 ] 可以直接得到到第 K+1元素的地址,从而可以访问该元素中的数据。该过程只进行了 1 次寻址的操作。

在查询链表中第 K+1 个元素时,一般情况下,会从链表的头节点依次通过next指针指向找到第 K+1个元素。该操作需要进行 K 次寻址的操作。

4. ArrayList源码分析

4.1 继承结构

 4.2 类结构

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
    // 序列化处理过程中验证传输类和本地类版本是否一致
    private static final long serialVersionUID = 8683452581122892189L;

    // 数组默认初始化容量
    private static final int DEFAULT_CAPACITY = 10;
    
    // 数组中当前包含的元素个数
    private int size;

    // 数据存储的数组
    transient Object[] elementData; 
    
    // 用于空实例的共享空数组实例
    private static final Object[] EMPTY_ELEMENTDATA = {};
   
    // 用于默认大小的空实例的共享空数组实例
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 	
    
    // 集合版本号,每次对集合进行增加和删除元素都会+1
    protected transient int modCount = 0;
    
    ...
}
  • ArrayList类继承了AbstractList抽象类和实现了List接口,表示ArrayList实例具备add,remove,set,get等最基本的位置操作。
  • ArrayList类实现了RandomAccess标记接口,标记ArrayList实例具备快速随机访问的能力。
  • ArrayList类实现了Cloneable标记接口,标记ArrayList实例可以被克隆。
  • ArrayList类实现了Serializable标记接口,标记ArrayList实例支持序列化,可以在网络中传输。
  • elementData成员变量被transient关键字修饰,表示elementData在ArrayList实例序列化处理的过程中会被忽略。因为在实际使用场景中,elementData可能不是满的,只有数据部分才需要序列化。所以ArrayList采用了重写writeObject方法和readObject方法来自定义elementData的序列化处理过程。
  • modCount成员变量的作用是用来触发fail-fast机制,下文会具体介绍。

4.3 初始化

4.3.1 无参构造器

public ArrayList()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值