ArrayList实现了List接口,它的底层数据结构是数组,因此获取容器中任意元素值的时间复杂度为O(1),新增或删除元素的时间复杂度为O(N)。每一个ArrayList实例都有一个capacity变量,capacity是ArrayList用于存储元素的容器大小,当有新元素添加到容器时,capacity会自动扩容,当新增元素时,容器会计算需要扩容的大小,减少了内存重新分配的次数。需要注意的时,ArrayList是非线程安全的容器,在多线程环境下容易出现线程安全问题。

源码

成员变量

private static final int DEFAULT_CAPACITY = 10; // 默认的容量是10

private static final Object[] EMPTY_ELEMENTDATA = {}; //初始化容量为0时的空数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //初始化没有指定容量

transient Object[] elementData; //存储元素的数组

private int size; //容器中元素的数量

构造方法

public ArrayList(int initialCapacity) {
//如果初始化指定容量 > 0,直接创建一个数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
} /**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; //默认的数组容量大小是10
}

添加元素


public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
} private void add(E e, Object[] elementData, int s) {
//容器元素数量等于数组的长度触发扩容条件
if (s == elementData.length)
//调用grow方法进行扩容
elementData = grow();
elementData[s] = e;
size = s + 1;
} //扩容逻辑,先计算出需要扩容的大小,再把原数组元素拷贝到扩容后的数组
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
} private Object[] grow() {
return grow(size + 1);
}
//计算扩容后的数组长度
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
// preconditions not checked because of inlining
// assert oldLength >= 0
// assert minGrowth > 0 int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}

通过源码可知,添加元素前,先判断当前容器大小与数组长度,决定是否要扩容,否则直接添加到容器中。扩容需要计算出扩容后新数组的长度,新数组长度是原数组的1.5倍大小。

在指定位置添加元素

public void add(int index, E element) {
//先判断插入位置是否合法
rangeCheckForAdd(index);
//记录容器被修改的次数
modCount++;
final int s;
Object[] elementData;
//扩容条件
if ((s = size) == (elementData = this.elementData).length)
elementData = grow();
//将后面的元素后移,腾出位置
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = element;
size = s + 1;
}

Java容器源码学习--ArrayList源码分析的更多相关文章

  1. JDK1.8源码学习-ArrayList

    JDK1.8源码学习-ArrayList 目录 一.ArrayList简介 为了弥补普通数组无法自动扩容的不足,Java提供了集合类,其中ArrayList对数组进行了封装,使其可以自动的扩容或缩小长 ...

  2. Java -- 基于JDK1.8的ArrayList源码分析

    1,前言 很久没有写博客了,很想念大家,18年都快过完了,才开始写第一篇,争取后面每周写点,权当是记录,因为最近在看JDK的Collection,而且ArrayList源码这一块也经常被面试官问道,所 ...

  3. 由JDK源码学习ArrayList

    ArrayList是实现了List接口的动态数组.与java中的数组相比,它的容量能动态增长.ArrayList的三大特点: ① 底层采用数组结构 ② 有序 ③ 非同步 下面我们从ArrayList的 ...

  4. Java入门系列之集合ArrayList源码分析(七)

    前言 上一节我们通过排队类实现了类似ArrayList基本功能,当然还有很多欠缺考虑,只是为了我们学习集合而准备来着,本节我们来看看ArrayList源码中对于常用操作方法是如何进行的,请往下看. A ...

  5. 从JDK源码学习Arraylist

    从今天开始从源码去学习一些Java的常用数据结构,打好基础:) Arraylist源码阅读: jdk版本:1.8.0 首先看其构造方法: 构造方法一: 第一种支持初始化容量大小,其中声明一个对象数组, ...

  6. java提高(8)---ArrayList源码

    ArrayList源码 一.定义 public class ArrayList<E> extends AbstractList<E> implements List<E& ...

  7. Java集合框架之一:ArrayList源码分析

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! ArrayList底层维护的是一个动态数组,每个ArrayList实例都有一个容量.该容量是指用来存储列表元素的数组的大小.它总是至少等于 ...

  8. Java集合源码剖析——ArrayList源码剖析

    ArrayList简介 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境下,多线 ...

  9. 【Java集合】试读ArrayList源码

    ArrayList简介 ArrayList 是一个数组队列,相当于 动态数组.与Java中的数组相比,它的容量能动态增长.它继承于AbstractList,实现了List, RandomAccess, ...

随机推荐

  1. C语言 指针数组指针

    指向指针数组的指针. 1 #include <stdio.h> 2 3 int main(void) 4 { 5 char *pa[4]={"aaaaa"," ...

  2. ubuntu安装配置ssh-connect to host localhost port 22: Connection refused

    在安装ssh,经常出现 ssh: connect to host localhost port 22: Connection refused 从以下几点去检查: 1.是否安装ssh-server: 打 ...

  3. 巩固javaweb第十五天

    巩固内容: 单选按钮: 在注册功能中,用户选择学历使用的是单选按钮,并且是多个单选按钮,每个选项对 应一个单选按钮,用户只能选择其中一个,这多个单选按钮的格式相同.如果用户要输入 的信息只有少数几种可 ...

  4. Spark集群环境搭建——Hadoop集群环境搭建

    Spark其实是Hadoop生态圈的一部分,需要用到Hadoop的HDFS.YARN等组件. 为了方便我们的使用,Spark官方已经为我们将Hadoop与scala组件集成到spark里的安装包,解压 ...

  5. spring boot 之监听器ApplicationListener

    监听器ApplicationListener 就是spring的监听器,能够用来监听事件,典型的观察者模式.ApplicationListener和ContextRefreshedEvent一般都是成 ...

  6. win32汇编基础

    win32汇编基础知识 Debug 版本|Release 版本 Debug 是"调试"的意思,Debug 版本就是为调试而生的,编译器在生成 Debug 版本的程序时会加入调试辅助 ...

  7. Java中特殊的类——Object类

    Java中特殊的类--Object类 1.Object类的概述 Object类是java默认提供的类.Java中除了Object类,所有的类都是有继承关系的.默认会继承Object类,即所有的对象都可 ...

  8. [学习总结]4、Android的ViewGroup中事件的传递机制(一)

    本文主要针对dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三个方法,通过简单的例子来简单的介绍下. 根据字面意思的理解,dispatchTo ...

  9. spring 事务处理中,同一个类中:A方法(无事务)调B方法(有事务),事务不生效问题

    public class MyEntry implements IBaseService{ public String A(String jsonStr) throws Exception{ User ...

  10. CentOS 6.4 下 Python 2.6 升级到 2.7

    一开始有这个需求,是因为用 YaH3C 替代 iNode 进行校园网认证时,CentOS 6.4下一直编译错误,提示找不到 Python 的某个模块,百度了一下,此模块是在 Python2.7 以上才 ...