ArrayList关键代码解析
以下代码是ArrayList中关键扩容代码解释:
- ArrayList底层使用数组存储数据;
- ArrayList默认容量是10;
- ArrayList默认扩容策略是原容量的1.5倍;
- ArrayList最大容量是Integer-8;
public class ArrayList{
/**
* 默认初始化数组容量:10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组(用于空实例),在实例化时如果传入的list长度为0,当调用new ArrayList(0)时,即传入的数组长度为0时,会默认 elementData=https://www.it610.com/article/EMPTY_ELEMENTDATA
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小实例的共享空数组实例,在调用new ArrayList()时会默认elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* 之所以与EMPTY_ELEMENTDATA区分开,以知道在添加第一个元素时容量需要增加多少。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存ArrayList数据的数组
*/
transient Object[] elementData;
/**
* ArrayList中元素的个数
*/
private int size;
/**
* 带初始容量参数的构造函数(用户可以在创建ArrayList对象时自己指定集合的初始大小)
*/
public MyArrayList(int initialCapacity) {
if (initialCapacity> 0) {
//如果传入的参数大于0,创建initialCapacity大小的数组
this.elementData = https://www.it610.com/article/new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果传入的参数等于0,创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
//其他情况,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}/**
* 默认的无参构造函数
* 初始化的时候默认容量是10,elementData是空数组,只有在添加第一个元素的时候才会真正的将elementData初始化成为一个容量为10的数组(相当于是延迟初始化)
*/
public MyArrayList() {
this.elementData = https://www.it610.com/article/DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}/**
* 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
* @param c
*/
public MyArrayList(Collection extends E> c) {
//将传入的集合转成数组
elementData = https://www.it610.com/article/c.toArray();
if ((size = elementData.length) != 0) {
//如果数组中元素长度不是0,判断数组类型是不是Object数组类型,如果不是则转成Object数组类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
//如果是一个空集合,则使用EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
}
}/**
* 裁剪ArrayList,主要是给程序员调用的,如果当前数组中元素个数小于整个数组的长度,则将数组缩减成与元素个数相同的数组,能够最小化该ArrayList占用的存储空间
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}/**
* 如有必要,增加此ArrayList实例的容量,以确保它至少能容纳元素的数量
* ArrayList的扩容机制
* @param minCapacity
*/
public void ensureCapacity(int minCapacity) {
//默认最小的扩容数量,如果elementData不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么默认最小扩容数量是10
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0
: DEFAULT_CAPACITY;
//如果最小容量大于已有的最大容量
if (minCapacity> minExpand) {
ensureExplicitCapacity(minCapacity);
}
}/**
* 计算需要扩展的容量大小,如果elementData是空数组,则返回默认容量大小,即10,否则返回minCapacity
* @param elementData
* @param minCapacity
* @return
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData =https://www.it610.com/article/= DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}/**
* 判断当前数组element能否保存minCapacity数量的元素,如果不能则进行扩容
* @param minCapacity
*/
private void ensureCapacityInternal(int minCapacity) {
//为了方便解析,将该行代码解析成为两行
//ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
//获取容量大小,即当elementData是默认的空数组时,则返回默认大小,即10
//如果elementData默认不是空数组时,则返回minCapacity
int capacity = calculateCapacity(elementData, minCapacity);
//判断elementData能否满足所需最小的容量,如果不能满足则扩容
ensureExplicitCapacity(capacity);
}/**
* 判断elementData能否满足所需最小的容量,如果不能满足则扩容
* @param minCapacity
*/
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
//如果所需最小容量(minCapacity)大于当前elementData数组的长度,则扩容
if (minCapacity - elementData.length> 0)
//扩容
grow(minCapacity);
}/**
* 为了防止OOM异常,限制数组分配的最大长度
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 进行扩容操作
* @param minCapacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
//获取当前elementData数组的长度
int oldCapacity = elementData.length;
//默认新的数组长度是现在数组长度的1.5倍 (oldCapacity+0.5*oldCapacity=1.5oldCapacity)
//位运算比直接newCapacity=1.5*oldCapacity要快很多
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0) {
//如果扩容1.5倍仍然小于指定要扩容(minCapacity)的数量
//则扩容至指定容量(minCapacity)的大小
newCapacity = minCapacity;
}//代码执行到这里,实际上最终要扩容的数量要么是现在elementData长度的1.5倍,要么是指定要扩容的长度(minCapacity)
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果最终要扩容的数量大于内置的最大值,即MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8
//则默认将最终要扩大的容量改为Integer.MAX_VALUE
newCapacity = hugeCapacity(minCapacity);
//将elementData扩容至newCapacity大小的数组,并且将现在elementData中的元素拷贝到新的数组中
elementData = https://www.it610.com/article/Arrays.copyOf(elementData, newCapacity);
}/**
*大容量
* 如果需要扩展的容量大于MAX_ARRAY_SIZE=Integer.MAX_VALUE-8,则返回MAX_ARRAY_SIZE,否则返回MAX_VALUE
* @param minCapacity
* @return
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity> MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}/**
* 新增一个元素
* @param e
* @return
*/
public boolean add(E e) {
//判断当前数组容量是否够用,如果不够,则进行扩容
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
}
【ArrayList关键代码解析】
推荐阅读
- CVE-2020-16898|CVE-2020-16898 TCP/IP远程代码执行漏洞
- 不废话,代码实践带你掌握|不废话,代码实践带你掌握 强缓存、协商缓存!
- 工具|后天就是七夕节,你准备好了吗(送上几个七夕代码,展示你技能的时候到了!)
- 写好铁线篆的几个关键窍门
- 越努力越幸福
- 《机器学习实战》高清中文版PDF英文版PDF+源代码下载
- 霍兰德职业代码对照表
- 二叉树路径节点关键值和等于目标值(LeetCode--112&LeetCode--113)
- Hexo代码块前后空白行问题
- 前端代码|前端代码 返回顶部 backToTop