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

ArrayList 源码分析

ArrayList 简介

ArrayList 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。

ArrayList 继承于 AbstractList ,实了 ListRandomAccessCloneablejava.io.Serializable 这些接口。

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
  • List : 表明它是一个列表,支持添加、删除、查找等操作,并且可以通过下标进行访问。
  • RandomAccess :这是一个标志接口,表明实现这个接口的 List 集合是支持 快速随机访问 的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
  • Cloneable :表明它具有拷贝能力,可以进行深拷贝或浅拷贝操作。
  • Serializable : 表明它可以进行序列化操作,也就是可以将对象转换为字节流进行持久化存储或网络传输,非常方便。

ArrayList 可以添加 null 值吗?

ArrayList 中可以存储任何类型的对象,包括 null 值。不过,不建议向ArrayList 中添加 null 值, null 值无意义,会让代码难以维护比如忘记做判空处理就会导致空指针异常。

示例代码:

ArrayList<String> listOfStrings = new ArrayList<>();
listOfStrings.add(null);
listOfStrings.add("java");
System.out.println(listOfStrings);

输出:

[null, java]

Arraylist 与 LinkedList 区别?

  • 是否保证线程安全: ArrayListLinkedList 都是不同步的,也就是不保证线程安全;
  • 底层数据结构: ArrayList 底层使用的是 Object 数组LinkedList 底层使用的是 双向链表 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
  • 插入和删除是否受元素位置的影响:
  • ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是 O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element)),时间复杂度就为 O(n)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。
  • LinkedList 采用链表存储,所以在头尾插入或者删除元素不受元素位置的影响(add(E e)addFirst(E e)addLast(E e)removeFirst()removeLast()),时间复杂度为 O(1),如果是要在指定位置 i 插入和删除元素的话(add(int index, E element)remove(Object o),remove(int index)), 时间复杂度为 O(n) ,因为需要先移动到指定位置再插入和删除。
  • 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList(实现了 RandomAccess 接口) 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
  • 内存空间占用: ArrayList 的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。

ArrayList 扩容机制分析

先从 ArrayList 的构造函数说起

ArrayList 有三种方式来初始化,构造方法源码如下(JDK8):

/*** 默认初始容量大小*/
private static final int DEFAULT_CAPACITY = 10;private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 默认构造函数,使用初始容量10构造一个空列表(无参数构造)*/
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}/*** 带初始容量参数的构造函数。(用户自己指定容量)*/
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {//初始容量大于0//创建initialCapacity大小的数组this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {//初始容量等于0//创建空数组this.elementData = EMPTY_ELEMENTDATA;} else {//初始容量小于0,抛出异常throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);}
}
/*** 默认初始容量大小*/
private static final int DEFAULT_CAPACITY = 10;private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** 默认构造函数,使用初始容量10构造一个空列表(无参数构造)*/
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}/*** 带初始容量参数的构造函数。(用户自己指定容量)*/
public ArrayList(int initialCapacity) {if (initialCapacity > 0) {//初始容量大于0//创建initialCapacity大小的数组this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {//初始容量等于0//创建空数组this.elementData = EMPTY_ELEMENTDATA;} else {//初始容量小于0,抛出异常throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);}
}

细心的同学一定会发现:以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为 10。 下面在我们分析 ArrayList 扩容时会讲到这一点内容!


http://www.mrgr.cn/news/57282.html

相关文章:

  • Unity Spine优化思路
  • Redis持久化机制RDB持久化和AOF持久化
  • HTTP协议介绍
  • LabVIEW提高开发效率技巧----图像处理加速
  • C++:set和map的使用指南
  • eIQ笔记(UI介绍+Loss曲线+OpenART例程)
  • 论文精读:TiC-CLIP: Continual Training of CLIP Models(二)
  • 搜维尔科技:使用CyberGlove数据手套控制机械手遥操作拿鸡蛋
  • LPDDR4/LPDDR4X讲解(一)
  • 香橙派、树莓派与Jetson的选择攻略:为您的项目找到最佳匹配
  • 【BJWC2008】王之财宝Gate Of Babylon——超详解
  • 时间同步协议有哪些?
  • 【redis】基础指令|数据结构总览|单线程架构分析
  • 为您的 Raspberry Pi 项目选择正确的实时操作系统(RTOS)
  • Java:抽象类和接口
  • Linux内核 -- `dynamic_debug` 使用指南
  • ELRS遥控器与接收机WIFI对频
  • python-----函数详解(一)
  • 组件可控个性化生成新方法MagicTailor:生成过程中可以自由地定制ID
  • libaom 编解码项目编码接口文件介绍
  • MySQL笔试面试题之AI答(2)
  • Docker 基础入门
  • 破四元!一区飞蛾扑火算法+时序卷积+双向单元+注意力机制!MFO-TCN-BiGRU-Attention多变量时间序列预测
  • MySQL优化手段有哪些
  • 好看的动态屏保来了 今年不能错过的视觉盛宴
  • pytorh学习笔记——cifar10(五)ResNet网络结构