ArrayList源码解析-Java8
2021-04-14 06:29
标签:val 指定位置 end oid 数组元素 返回 关键字 检测 null 一.ArrayList介绍 二.ArrayList源码分析 2.1 重要的属性 2.2 构造方法 2.3 添加元素 2.4 数组扩容 2.5 删除元素 2.6 数组缩容 2.7 获取元素 ArrayList在平时开发过程中使用得特别频繁,它的底层是使用数组,存在线程并发安全(并发读写); 与之密切相关的Vector,功能和ArrayList几乎一样(源码也几乎一样),但是Vector是并发安全的,因为Vectory的接口,大多是在方法上加了synchronized关键字进行同步操作,达到并发安全的效果。 ArrayList有三个构造方法,需要注意的是,使用无参构造方法来创建ArrayList时,不会创建数组,也就是说不会分配数组内存空间。代码如下: 添加新元素,常用的就是追加新元素和在指定位置插入新元素。 需要注意的是,ArrayList总是在真正插入元素前判断是否需要扩容,如果需要扩容,则扩容后,再插入新元素;不需要扩容则直接插入元素。 前面每次add的时候,都会调用ensourCapacityInternal(size+1),这个方法里面就会判断是否需要进行扩容,如果需要扩容则会进行扩容操作。 除此之外,该方法还有另外一个重要的操作,就是modCount++,记录数组的变化次数,用于快速失败。 从源码中可以看出,当底层数组满的时候(插入新元素,size+1,超过底层数组的容量),则需要进行扩容,扩容时,会创建1.5倍旧数组的新数组,并将旧数组的元素拷贝到新数组中(顺序不会变)。 删除元素有两种方式,分别是删除指定元素和删除指定下标的元素。 删除元素之后,如果删除的不是最后一个元素,则需要将删除元素后面的元素往前挪一个位置,并将空出来的最后一个位置置位null(help GC)。 可以思考这种场景,一个ArrayList,刚开始初始容量为0,添加元素后,容量分别调为10、16...1024,但是后期数组元素在不断的删除元素,虽然数组中只剩下了5个元素,但是数组的长度是1024,这是极大地浪费,此时需要进行缩容,就是让底层数组调整为适合长度,最适合的长度就是刚好和元素数量个数相同。 ArrayList提供了trimToSize方法,就是进行缩容操作,将底层数组设置为刚好装下现有元素的长度 获取元素的过程,比较简单: 原文地址:https://www.cnblogs.com/-beyond/p/13254542.html ArrayList源码解析-Java8 标签:val 指定位置 end oid 数组元素 返回 关键字 检测 null 原文地址:https://www.cnblogs.com/-beyond/p/13254542.html目录
一.ArrayList介绍
二.ArrayList源码分析
2.1 重要的属性
/**
* 默认容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 共享的静态变量(一个空的数组)
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认空容量的数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存ArrayList中元素的真实数据,使用transient表示序列化时不计入该字段
*/
transient Object[] elementData;
/**
* 记录ArrayList中元素的个数
*/
private int size;
/**
* 允许申请的最大容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
2.2 构造方法
public ArrayList() {
// 无参构造方法,直接将保存数据的elementData设置为空数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(int initialCapacity) {
// 传入的初始容量大于0,则会创建指定容量长度的数组
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果传入的初始容量为0,则指定为空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 容量小于0,属于非法参数,直接抛出异常
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
}
public ArrayList(Collection extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class) {
// 将传入的集合复制到数组中
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
} else {
// 如果传入的集合为空,那么直接设置为空的数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
2.3 添加新元素
/**
* 添加新元素(append)
*
* @param e 新元素
*/
public boolean add(E e) {
// 判断是否需要扩容(元素数量+1 如果超过数组容量,则会进行扩容)
ensureCapacityInternal(size + 1);
// 将新元素放到最后一个元素后面(同时元素数量加1)
elementData[size++] = e;
return true;
}
/**
* 将新元素插入指定位置
*/
public void add(int index, E element) {
// 检测index是否越界
rangeCheckForAdd(index);
// 检测是否需要扩容(若需要,则进行扩容),同时修改modCount+1
ensureCapacityInternal(size + 1);
// 将index后面元素统统往后移动一个位置,空出index位置
System.arraycopy(elementData, index, elementData, index + 1, size - index);
// 将新元素放入index位置
elementData[index] = element;
// 元素数量加1
size++;
}
/**
* 检测指定的index是否越界
*/
private void rangeCheckForAdd(int index) {
if (index > size || index
2.4 数组扩容
/**
* 确保内部数组的容量满足minCapacity
*
* @param minCapacity 期望的最小容量
*/
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
/**
* 计算容量(正确容量)
*
* @param elementData 保存元素的数组
* @param minCapacity 期望的最小容量
* @return 确定容量
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果数组为空数组,那么就取minCapacity和默认容量10的较大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 数组不为空,直接返回minCapacity
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
// 记录数组的修改次数
modCount++;
// 是否minCapacity超过当前数组的长度(当前容量),证明需要扩容(扩容的时机,重要!!!!)
if (minCapacity - elementData.length > 0) {
grow(minCapacity);
}
}
/**
* 数组扩容
*
* @param minCapacity 希望扩容后的数组长度
*/
private void grow(int minCapacity) {
int oldCapacity = elementData.length; // 旧数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1); // 新数组的容量(旧数组的1.5倍)
// 判断计算后的新数组容量是否满足要求的最小容量
// 如果不满足,则直接将新数组的容量设置为需要的容量
if (newCapacity - minCapacity 0) {
newCapacity = hugeCapacity(minCapacity);
}
// 申请一个新数组(新容量),然后将原数组的数据拷贝到新数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
2.5 删除元素
/**
* 删除指定位置的元素
*/
public E remove(int index) {
// 判断数组是否越界
rangeCheck(index);
// 修改次数加1
modCount++;
// 从数组中返回下标为index的元素
E oldValue = elementData(index);
// 计算需要移动的元素数量
int numMoved = size - index - 1;
// 如果需要移动的元素数量大于0(也就是删除的元素不是最后一个元素)
// 则将index+1开始元素一次往前移动一个位置
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
// 将最后一个元素的位置删除(置位null,让GC的时候清除对应的内存)
elementData[--size] = null;
// 返回被删除的元素
return oldValue;
}
/**
* 判断数组是否越界
*
* @param index 指定数组下标
*/
private void rangeCheck(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
/**
* 返回数组中下标为index的元素
* @param index
* @return
*/
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
/*--------------------------------------------------------*/
/**
* 删除指定元素(遍历数组中的元素,删除第一个匹配的元素)
*
* @return true:删除元素; false:未找到要删除的元素
*/
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
// 将数组空出的最后一个位置置位null(GC时清除元素),然后数组元素减1
elementData[--size] = null; // clear to let GC do its work
}
2.6 数组缩容
/**
* 缩容操作,将底层数组组调整为size长度
*/
public void trimToSize() {
// 修改次数加1
modCount++;
// 如果数组中的元素数量小于数组的长度,才进行缩容
// 如果数组中没有元素,则将底层数组切换为一个空数组,否则就换为size大小的数组
if (size
2.7 获取元素
/**
* 返回ArrayList中index下标的元素
*/
public E get(int index) {
// 数组越界检测
rangeCheck(index);
// 返回index下标的元素
return elementData(index);
}
/**
* 判断数组是否越界
*
* @param index 指定数组下标
*/
private void rangeCheck(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
}
/**
* 返回数组中下标为index的元素
*
* @param index
* @return
*/
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
上一篇:Java——构造方法
下一篇:vba基础5 时间处理
文章标题:ArrayList源码解析-Java8
文章链接:http://soscw.com/index.php/essay/75548.html