ArrayList源码浅要分析

以调用无参构造方法的方式创建ArrayList对象:(JDK9)
1.ArrayList list = new ArrayList();
创建ArrayList时,调用ArrayList类中的无参构造方法
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
由此可知:当调用无参的构造方法创建ArrayList()对象时,
会将常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值
给成员变量elementData

DEFAULTCAPACITY_EMPTY_ELEMENTDATA的源码:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
这是一个空的Object []类型的常量

elementData的源码:
transient Object[] elementData;
这是一个引用类型:Object[] 类型的变量

**小结:使用无参构造方法创建ArraList对象时,实际
上是在底层创建了一个空Object类型的数组,并
且该数组的地址是不可变得;并且将该数组的地
址复制给elementData变量,用它来记录该数组。**

2.使用add(E e)方法进行添加元素时:
add(E e)方法的源码:
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
就是说当添加数据时,会执行add(e, elementData, size);
e是要添加的对象,elementData是ArrayList集合底层维护的数组,
size是成员变量,既然是成员变量,那么就有初始值,因为size的
数据类型是int,所以size的初始值为0;
所以说:添加第一个数据的时候,调用add(e, elementData, size)方法,传入的
参数就是:add(要添加的对象,底层数组,0);
现在进入到add(e, elementData, size);方法:
源码:
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
进入方法执行后,会首先判断s的值与底层数组的长度是否相等,因为底层数组目前的
长度为0,而传入的参数s就是成员变量size,也是0;索引就会执行elementData = grow();
因为elementData 也是一个Object[]类型的成员变量,所以可以断定grow()方法的返回值
就是一个Object[]类型的数据。现在进入grow()方法:
源码:
private Object[] grow() {
return grow(size + 1);
}
返回值是grow(size + 1)的返回值,现在进入grow(size + 1)方法:
源码:
private Object[] grow(int minCapacity) {
return elementData = Arrays.copyOf(elementData,
newCapacity(minCapacity));
}
调用Arrays.copyOf()方法,这是一个扩容机制,参数1:elementData是底层数组,
将底层数组当做参数传递给copyOf()方法,参数2是新数组的长度,返回值是扩容后的数组,
在这里使用的是elementData来接受新数组的地址,那么集合的底层数组就不在是之前的那
个空的数组了,而是扩容后的新数组。那么newCapacity(minCapacity))是什么,现在进入
newCapacity(minCapacity))的方法:
源码:
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
第一次执行的时候:
oldCapacity:旧数组的长度;因为现在是往里面存第一个元素,也就是第一次往里面存数据,所以
旧数组的长度是0
newCapacity :新数组的长度;是旧数组的1.5倍,因为目前旧数组长度为0,那么新数组的长度也是0;
那么:newCapacity - minCapacity = -1<0;
那么执行:return Math.max(DEFAULT_CAPACITY, minCapacity);
返回值就是:DEFAULT_CAPACITY;而DEFAULT_CAPACITY是ArrayList的成员变量,初始值为10;
因此,第一次执行的时候,newCapacity(int minCapacity)的返回结果就是10;

那么Arrays.copyOf(elementData,newCapacity(minCapacity))就是:
(elementData,10);
所以grow(int minCapacity)方法里面返回的就是长度为10的Object类型的数组:elementData;
所以grow()方法返回的就是长度为10的Object数组:elementData;
所以在add(E e, Object[] elementData, int s)方法中:
elementData = grow();就是把grow()的返回值长度为10的新数组的地址复制给elementData;
elementData[s] = e;就是把要存放的元素,放在0索引上
size = s + 1;保证成员变量size的自增,以保证再次存放元素时,存放的是下一索引位置的
元素,因为在add()方法中调用private void add(E e, Object[] elementData, int s)方法时,
int s 的值,传递的就是size;
至此,添加第一个元素执行完毕;
执行网private void add(E e, Object[] elementData, int s)方法后,返回true,告知调用者,
添加元素成功;

**小结:调用无参构造方法创建一个ArrayList对象后,底层的数组长度是为0的,只有当调用add()方法添加
元素时,才会扩容为10;当没存满10个元素时,此时那么在此调用add()方法,那么就会再次调用:
private void add(E e, Object[] elementData, int s),当执行到:
if (s == elementData.length)时,s是小于数组长度的,那么就会直接执行:
elementData[s] = e;,将要添加的元素添加到数组里面去

当存满10个元素,再次存储下一元素时,size的值是10,那么s的值就是10,那么s == 数组长度;
那么就会继续执行grow()方法:
进入grow()方法后,就会执行grow(int minCapacity),传递的参数是size+1,那么就是10+1 = 11;
进入grow(int minCapacity)方法后,就会执行Arrays.copyOf(elementData,newCapacity(minCapacity));
那么就会执行newCapacity(minCapacity)),参数值为11;
进入newCapacity(minCapacity))方法后:
oldCapacity(数组长度) = 10;
newCapacity = 15;
那么就会计算:newCapacity - minCapacity <= 0;结果为:15-11>0,因此为:false;
那么就会返回执行:
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
那么就会计算:newCapacity - MAX_ARRAY_SIZE <= 0,
MAX_ARRAY_SIZE:常量:值大约为int类型的最大值;
因此,只要newCapacity在int范围内,就会执行:
return newCapacity;
那么: Arrays.copyOf(elementData,newCapacity(minCapacity))执行完毕,就是讲旧数组的元素拷贝到新数组中,并且
新数组的长度+原来数组长度的1/2;此时是第一次扩容,新数组的长度为15;
最终新数组返回给add(E e, Object[] elementData, int s),赋值为elementData变量;
然后执行:elementData[s] = e
那么就将要添加的对象添加在了第11号的位置,也就是10索引的位置;
以后再次添加,知道最后一个索引存上时,再次存储就再次扩容。**

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值