ArrayList源码学习

本文深入解析了ArrayList的内部实现机制,包括其线程安全性、数组扩容策略及元素添加流程。详细介绍了ArrayList在不同情况下的最小数组容量计算方法,以及如何通过判断当前数组长度与最小容量的关系来决定是否进行扩容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayList:线程不安全,内部使用一个数组实现

transient Object[] elementData; // non-private to simplify nested class access

无参构造函数源码:

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
//...DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
//说明ArrayList使用无参构造时,初始内部为空数组。

调用add方法添加元素

ArrayList进行add操作时,会获取一个"最小数组容量",
(如果此时数组为空数组,最小数组容量为10,否则为当前元素个数加一)
然后将最小容量与当前数组长度比较,以判断是否需要扩容。
最后再进行赋值操作

add(E)方法:

ensureCapacityInternal(size + 1);  
elementData[size++] = e;
//注意size+1临时赋值给了minCapacity。
//这个minCapacity将会多次出现,意为最小数组容量

进入ensureCapacityInternal(int minCapacity)方法:

 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
 //elementData:{},minCapacity:1
 //在这个方法里调用了两个方法:分别是calculateCapacity方法(返回最小数组容量)
                                ensureExplicitCapacity方法(判断是否扩容)

进入calculateCapacity(Object[] elementData, int minCapacity)方法(这个方法主要作用是返回最小数组容量):

 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
 return minCapacity;
//判断内部数组是不是空数组
//是的话返回DEFAULT_CAPACITY:10和minCapacity:1的较大者->10
//不是的话直接返回minCapacity->当前元素个数加一

此时返回到了ensureCapacityInternal方法中,获取到了最小数组容量,接着调用ensureExplicitCapacity方法以判断数组是否进行扩容

ensureExplicitCapacity(int minCapacity)方法( 判断数组是否扩容)

modCount++;//元素个数加一
if (minCapacity - elementData.length > 0)
//如果minCapacity(最小数组容量)大于当前数组长度(if成立),那么进行扩容
grow(minCapacity)

grow(int minCapacity)方法(扩容)

int oldCapacity = elementData.length;
//旧容量为数组长度。空数组情况下即为0
int newCapacity = oldCapacity + (oldCapacity >> 1);
//新容量为旧容量的1.5倍。空数组情况下也为0,因为0*1.5=0
if (newCapacity - minCapacity < 0)
//新容量小于数组最小容量时,将新容量重新赋值为数组最小容量。
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//扩容
elementData = Arrays.copyOf(elementData, newCapacity);

grow方法执行完后会回到add方法,最后才执行元素的赋值操作

elementData[size++] = e;

概括:
使用无参构造函数初始化ArrayList时,内部数组为空数组。
ArrayList进行add操作时,会先获取一个最小数组容量(上面的minCapacity)。
如果此时数组为空数组,最小数组容量为10,否则就为当前元素个数加一。

return Math.max(DEFAULT_CAPACITY, minCapacity);

紧接着进行一次判断:

if (minCapacity - elementData.length > 0)
//如果当前数组长度大于最小数组容量(无需扩容),那么直接添加元素。
//如果当前数组长度小于最小数组容量,那么就会进行数组的扩容(grow)。

扩容时需要一个新容量(newCapacity),新容量为旧容量(oldCapacity)的1.5倍。

int newCapacity = oldCapacity + (oldCapacity >> 1);

但是如果此时为空数组的话,那么新容量也为0。因为旧容量为0,而0*1.5=0。
所以会进行一次判断,新容量小于最小长度时,将新容量重新赋值为最小容量。

if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);

最后再使用这个新容量对数组进行扩容。扩容完毕后,最后再进行元素的赋值。

elementData = Arrays.copyOf(elementData, newCapacity);
...
elementData[size++] = e;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值