list.add方法源码分析
前言:本人第一次写文章,如果文章中有地方表达的不够正确或不清楚请指出来,我会加以改正。还请多多包含。
正文:相信在日常撸代码的过程中大家用到ArrayList集合中的场景不算少数,今天我也是突发奇想,想看下ArrayList是怎么实现的。这篇文章主要讲它的add()方法,在这之前先说明一下ArrayList中add()方法内使用到的属性,方便大家对add()方法的理解。
//用来装载数据的容器,我们向list中添加的数据其实是存在这个数组当中的。
transient Object[] elementData;
// 一个空的数组。 作用:用来初始化 elementData 数组。(数组的初始化有好几种方式,不知道可以百度的,这里就不说了。)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 在不指定 list 长度大小情况下的默认初始长度
private static final int DEFAULT_CAPACITY = 10;
// Integer的最大值-8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 数组内元素的个数
private int size;
以上就是在add() 方法种所使用到的对象了。
以下是add()的源码及每行代码的解释
/**
* Appends the specified element to the end of this list.(将指定的元素追加到列表的末尾)
* 参数是你要添加的元素
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
// 这是一个方法 功能:用来检查是否首次向list中添加数据,并给定初始的容量大小(10)
ensureCapacityInternal(size + 1); // Increments modCount!!
// 向list中添加数据 并让size在原有的基础上+1(首次添加时size=0,添加完后size++ ,size的值就变成了1, size++ 是先执行,后运算。
// ++size 是先运算,后执行。)
elementData[size++] = e;
// 无论如何都返回true
return true;
}
下边说 ensureCapacityInternal(size +1) 这个方法,在此方法中又调用了其他的方法,下边会依次列出并详解。
private void ensureCapacityInternal(int minCapacity) {
// 在这一步它判断了是否是首次向list中添加数据,如果是首次那么它一定相等。(原因可以看ArrayList的无参构造方法,它里边有这样一句
// this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA 。 )
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 这个方法返回两个值中最大的一个值,如果说首次添加数据那么它会返回 DEFAULT_CAPACITY(10)并赋值给 minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//这个方法用来检查是否需要扩容
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity(minCapacity);
private void ensureExplicitCapacity(int minCapacity) {
// 这个变量用来记录list的修改次数,它是由ArrayList继承AbstractList抽象类得来的。
modCount++;
// overflow-conscious code
//这里判断数组的长度 如果新元素添加后的数组长度大于当前数组的长度,那么他就需要进行一次1.5倍的扩容。
if (minCapacity - elementData.length > 0)
//调用扩容方法
grow(minCapacity);
}
grow(minCapacity);
//增加elementData 数组的容量
private void grow(int minCapacity) {
//当前数组的长度
int oldCapacity = elementData.length;
//使用位运算符扩容至当前数组长度的1.5倍 newCapacity :扩容后的长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
//检查扩容后的长度是否小于新元素添加后的数组长度,如果小于就将新元素添加后的长度赋值给 newCapacity
// newCapacity - minCapacity < 0 等同于 newCapacity < minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// MAX_ARRAY_SIZE 的值是:Integer.MAX_VALUE - 8 (这个方法基本用不到用到)。
// hugeCapacity(int minCapacity)方法会在下段代码中贴出来
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将当前数组以及要扩容的数组长度放到这个copyOf方法当中(不明白的话可以自己创建个数组然后用下这个方法,挺简单的。)
// 在这一步就完成了数组的扩容了,如果不发生意外情况的话(意外情况就是 if (newCapacity - MAX_ARRAY_SIZE > 0)这一步),
// 所扩容的长度将是原数组的 1.5 倍
elementData = Arrays.copyOf(elementData, newCapacity);
}
hugeCapacity(minCapacity)
private static int hugeCapacity(int minCapacity) {
// 检差参数是否小于零 否则抛出内存溢出异常
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 如果大于0的话 就比较是否大于 MAX_ARRAY_SIZE( MAX_ARRAY_SIZE值是:Integer.MAX_VALUE - 8)
// 如果不大于就返回 MAX_ARRAY_SIZE 反之则返回 Integer.MAX_VALUE
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
到这一步其实关于扩容的就全部执行完勒,下边就回到最开始的地方
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
// 开始执行这里,将元素添加到数组当中,然后size的值 +1 最终返回结果true
elementData[size++] = e;
return true;
}
上边说的就是add(E e)这个方法了,下次有时间会把add(int index,E e)这个方法单独在写一个文章,文中如果有不对的地方,还请指正,大家一起进步成长。
如果觉得还不错的话就留个赞再走呗。