小伙伴们,大家好。前几周好像是得了甲流,一直发烧、感冒,学习劲头也不是很足。今天终于有心情读读源码写写文章了。我们先找个软柿子捏捏。
类结构

-
Serializable
接口:序列化接口 -
Cloneable
接口:可克隆接口 -
RandomAccess
接口:支持随机访问(通过下标的形式访问元素) -
List
接口 -
AbstractList<E>
抽象类 -
AbstractCollection<E>
抽象类 -
Collection<E>
接口 -
Iterable<T>
接口
属性
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认初始化容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组实例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 空数组实例 和 EMPTY_ELEMENTDATA 有区分
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 元素数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 元素数量
*/
private int size;
}
-
Object[] elementData
:用于存放元素的数组(数组的长度并一定等于元素个数) -
int size
:用于记录元素的个数 -
int DEFAULT_CAPACITY
:默认的数组长度大小为10 -
Object[] EMPTY_ELEMENTDATA
:长度为0的数组实例(手动设置初始容量为0时使用) -
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA
:长度为0的数组实例(无参构造方法时使用)
构造方法
ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
无参构造方法,元素数组
elementData
默认赋值DEFAULTCAPACITY_EMPTY_ELEMENTDATA
空数组实例
ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
initialCapacity
的取值范围:[0,Integer.MAX_VALUE]
当指定 initialCapacity=0
时,元素数组elementData
默认赋值EMPTY_ELEMENTDATA
空数组实例
ArrayList(Collection<? extends E> c)
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 {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
当 c.toArray()
的元素个数为0时,元素数组elementData被赋值EMPTY_ELEMENTDATA
空数组实例当 c.toArray()
的元素个数不为0时
若数组是 Object[]
类型,则无须任何操作,方法结束若数组不是 Object[]
类型,则转换成Object[]
类型
get(int index)
方法
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
-
rangeCheck(int index)
:检查index的值是否越界 -
elementData(int index)
:获取元素
rangeCheck(int index)
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
方法判断index不能够大于等于size,否则抛出异常。 如果大家传负值,这里不会报错
elementData(int index)
E elementData(int index) {
return (E) elementData[index];
}
代码也相当的简单,直接通过下标访问数组,并强转一次。
add(E e)
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public boolean add(E e) {
add(size(), e);
return true;
}
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
}
add(E e)
方法在抽象类中,并提供一个add(int index, E element)
让其子类重写,这里插入位置index为size,下面进入其子类ArrayList#add(int index, E element)
的具体实现
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
}
ArrayList
的实现逻辑如下
rangeCheckForAdd(int index)
:判断插入位置index是否在数组下标范围内[0,size]ensureCapacityInternal
:确保数组长度大于当前size+1
通过复制的方式移动数组,将index位置空出来 将index位置设置为被插入元素 size++
rangeCheckForAdd(int index)
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
方法十分简单易懂,判断index要在[0,size]范围,否则抛出异常
ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
该方法为了确保元素数组
elementData
的长度足够
如果元素数组 elementData
为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
,则会取minCapacity
和DEFAULT_CAPACITY
中较大的一个作为minCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
进入
ensureExplicitCapacity
方法,modCount
会自增。如果当前的数组元素elementData
长度不够(小于minCapacity
),则进行扩容。扩容方法咱们后面细说
元素移动
public void add(int index, E element) {
//..................
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//..................
}
从
index
位置开始,移动size-index
个元素到index+1
开始的位置

add(int index, E element)
指定位置插入,是直接跳到了
ArrayList
中的add(int index, E element)
就是上面分析的内容,这里就不重复分析了。
remove(int index)
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
index检查是否越界 modCount++记录一次修改 获取index位置的元素值 计算出移动的元素个数 size-index-1
将删除位置后的元素向前移动 size-1的位置设置为空,size=size-1 返回老数据

扩容grow(int minCapacity)
好的,我们这里专门看一下
ArrayList
的扩容机制
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
-
新的数组大小等于 oldCapacity + (oldCapacity >> 1)
oldCapacity >> 1
等价于oldCapacity/2
。 所以新数组大小为老数组的1.5倍
-
若老数组扩容1.5倍后还是小于 minCapacity
则新数组的长度就是minCapacity
-
若新数组大小比 MAX_ARRAY_SIZE
还要大,则通过minCapacity
重新计算新的数组长度 -
通过 Arrays.copyOf
进行数组复制扩容
总结
以上就是XiXi关于ArrayList
的创建、新增元素(扩容)、删除元素、查询元素相关代码的阅读,总结下来就几点
-
ArrayList
底层就是一个Object[]
数组,默认初始化大小为10,且在首次add元素时才初始化数组长度为10 -
ArrayList
插入和删除元素会移动元素位置,使用复制的方式完成 -
ArrayList
每次扩容原数组长度的1.5倍 -
ArrayList
的新增和删除操作均会导致modCount
的自增
原文始发于微信公众号(溪溪技术笔记):JDK8源码阅读-ArrayList
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/207092.html