文章目录
前言
本文主要编写ArrayList源码关于remove()方法及get()方法。
关于ArrayList源码的初始化化及add()方法源码可以看看我这篇文章: ArrayList新增元素源码分析
一、ArrayList中的删除方法
1、remove(Object o)
输入一个元素,将数组中第一个这个元素·删掉
remove(Object o)源码:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
//进行删除
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
//进行删除
fastRemove(index);
return true;
}
}
return false;
}
通过源码我们可以看出这段代码逻辑很简单,就是一个简单的遍历对象数组elementData,比较值,如果相同进行删除操作
fastRemove(int index)源码部分:
private void fastRemove(int index) {
//记录集合被修改次数
modCount++;
//需要移动的长度
int numMoved = size - index - 1;
if (numMoved > 0)
//如果删除的不是最后一个元素,将删除的元素到最后的元素整块前移
System.arraycopy(elementData, index+1,
elementData, index, numMoved);
//将最后对象数组最后一个元素设置为空,在下一次gc时回收空间
elementData[--size] = null; // clear to let GC do its work
}
2、E remove(int index)
传入一个下标,将该下标中的元素删除
E remove(int index)源码:
public E remove(int index) {
//判断index是否合法
rangeCheck(index);
//操作次数+1
modCount++;
//获得需要删除的元素
E oldValue = elementData(index);
//计算需要移动的长度
int numMoved = size - index - 1;
if (numMoved > 0)
//如果删除的不是最后一个元素,将被删除元素到最后一个元素向前移动
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//将最后对象数组最后一个元素设置为空,在下一次gc时回收空间
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
rangeCheck(int index)源码部分
//判断index是否小于数组长度,如果不是,直接抛异常
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
3、removeAll(Collection<?> c)
该方法传入一个集合将原数组和c的交集元素删掉
removeAll(Collection<?> c)源码:
public boolean removeAll(Collection<?> c) {
//判断c是否为空,如果为空抛异常
Objects.requireNonNull(c);
//进行删除
return batchRemove(c, false);
}
batchRemove(Collection<?> c, boolean complement)源码部分:
private boolean batchRemove(Collection<?> c, boolean complement) {
//将原数组拿出来
final Object[] elementData = this.elementData;
//r:原数组下标,w:新数组下标
int r = 0, w = 0;
//删除成功标志
boolean modified = false;
try {
for (; r < size; r++)
//complement是FALSE
//所以出中没有该元素就将该元素放入新数组中
//就是将删除的数据剔除,将其他数据依次向前提
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
//正常来说r是等于size的,try有异常时,r就不等于size
//因此,该方法是为了解决运行时异常的问题
//将r下标后的未比对的元素,在copy新数组的时候不改变他们的位置
if (r != size) {
//arraycopy(源,源的起始位置,目标,目标的起始位置,要从源移动的长度)
//elementData[w]这个的元素前一个元素是要操作数的最后一位元素,也就是elementData[w]是旧集合中(可能不符合)的元素。
//elementData[r]就是被异常停止的位置。size-r是为未比对的元素的长度
//该语句就是把未比对的元素,拼接在已经覆盖元素的后面。
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
//
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
//记录修改次数,防止出现数据混乱
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
小结remove
remove(Object o)方法比remove(int index)方法相比,前者需要遍历数组,而后者仅需要判断index是否合法,因此前者效率没有后者高,推荐使用后者进行删除
二、ArrayList中的获取方法
1.get(int index)
源码如下:
public E get(int index) {
//判断index是否合法,当他大于size时直接抛出异常
rangeCheck(index);
//获取元素
return elementData(index);
}
//elementData方法
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
总结
以上就是ArrayList中除添加方法外较为重要的源码分析,有什么问题或者建议欢迎来评论区交流。