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;
}

最新文章

  1. 如何让NGUI的对象在3D模型之上
  2. JDK中的native2ascii命令详解
  3. ffmpeg2.2在ubuntu下使用NDK编译——并在android工程下测试使用
  4. Rich控件二
  5. Ewebeditor最新漏洞及漏洞大全
  6. HDOJ --- 1176 免费馅饼
  7. Oracle 获取表结构信息
  8. Python学习笔记一,输入输出
  9. DFT 展开式和 FFT推导
  10. 交换机的Ethernet Channel
  11. 网络安全第一集之【SQL注入:sqlmap入门】
  12. HTTP协议那些事儿(Web开发补充知识点)
  13. PRML读书笔记_绪论曲线拟合部分
  14. 什么是RUP
  15. 【HDOJ4612】【双连通分量缩点+找树的直径】
  16. KubeletNotReady runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
  17. i18n实现前端国际化(实例)
  18. Celery(一个懂得 异步任务、定时任务、周期任务 的&quot;芹菜&quot;)
  19. thrift框架总结,可伸缩的跨语言服务开发框架
  20. Raspberry Pi 配置

热门文章

  1. Codeforces 923E - Perpetual Subtraction(微积分+生成函数+推式子+二项式反演+NTT)
  2. CSP-S2021 挂分记
  3. 59. Divide Two Integers
  4. SourceTree git 工作流
  5. Excel-条件判断
  6. R语言中的正则表达式(转载:http://blog.csdn.net/duqi_yc/article/details/9817243)
  7. javaSE高级篇1 — 异常与多线程基础
  8. 用友低代码开发平台YonBuilder首次亮相DevRun开发者沙龙
  9. act.四级
  10. 监控网站是否异常的shell脚本