文章目录
- Java简单集合
- ArrayList
- 继承体系
- 源码解析
- 总结
大家好哈,欢迎来到令狐小哥本期专栏,这期专栏主要是带着大家阅读JDK源码,我会分几期篇幅来介绍这个jdk源码、会进行剖析、梳理,欢迎大家指正阅读。后面我会配套自己的视频进行讲解~
Java简单集合
ArrayList
ArrayList是一种以数组实现的List,与数组相比,它具有动态扩展的能力,因此又被称为:动态数组。
继承体系
ArrayList
实现了List
,Serializable
,RandomAccess
,Cloneable
。
ArrayList
实现了List
,提供了基础的添加,删除,遍历等操作。ArrayList
实现了Serializable
,表示可以被序列化。ArrayList
实现了Cloneable
,可以被克隆。ArrayList
实现了RandomAccess
,提供了随机访问的能力。
源码解析
/**
* @Description: 源码阅读:Codelinghu
* @param null
* @return:
* @Author: codelinghu
* @Date: 2024/6/4
*/
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* ArrayList默认的容量为10
* default_capacity
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组,如果传入的容量为0的时候使用,
* 当new ArrayList(0)的时候使用它
*
* empty_elementdata
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
当new ArrayList()的时候使用它,使用这个空数组
defaultcapacity_empty_elementdata
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
存储元素的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
*集合中元素的个数
*/
private int size;
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//如果初始化容量大于0,新建一个数组存储元素
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果初始化容量等于0,使用空数组EMPTY_ELEMENTDATA
this.elementData = EMPTY_ELEMENTDATA;
} else {
//如果初始化容量小于0,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 无参构造,new ArrayList()的情况
*/
public ArrayList() {
//如果不传初始容量,初始化为DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,会在添加
//第一个元素的时候扩容为默认的大小,10.
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
这个构造器会传入一个集合C,这里会使用传入集合的元素拷贝到elementData数组中
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
/**
如果elementData的类型不是Object[],则使用Arrays.copyOf()方法将
elementData复制到一个新的Object[]类型的数组中。这样做的目的是确保elementData的
类型是Object[],避免类型不匹配的问题。
* @Author: codelinghu
* @Date: 2024/6/4
*/
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);// elementData复制到一个新的Object[]类型的数组中。这样做的目的是确保elementData的类型是Object[],避免类型不匹配的问题。
} else {
// 传入元素个数为0的时候replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
//计算最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//最小也得为10,避免容量过小导致频繁扩容
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
//检查是否需要扩容
private void ensureCapacityInternal(int minCapacity) {
//首先调用calculateCapacity(elementData, minCapacity)最小容量
//然后调用ensureExplicitCapacity()进行扩容~
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//传递最小容量过来,进行扩容~
private void ensureExplicitCapacity(int minCapacity) {
/**
首先将modCount加1,表示数组结构发生了变化。然后判断
minCapacity - elementData.length > 0,如果为真,说明需要扩容,
调用grow(minCapacity)方法进行扩容。
*/
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)//目前数组需要的容量大于当前的容量大小
grow(minCapacity);//说明需要扩容
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
数组扩容方法grow
minCapacity为需要的容量
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新容量为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量小于需要的容量,则以需要的容量为准!
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//如果新容量超过了最大的容量,则使用最大的容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
//hugeCapacity(minCapacity)方法用于计算ArrayList的最大容量
newCapacity = hugeCapacity(minCapacity);
// 以新容量拷贝出一个新数组
/**
将原数组(elementData)的内容复制到一个新数组中,并确保新数组的容量(newCapacity)
足够容纳更多的元素。这样,当向ArrayList添加更多元素时,就不需要频繁地进行扩容操作,
* @Author: codelinghu
* @Date: 2024/6/5
*/
elementData = Arrays.copyOf(elementData, newCapacity);
}
//计算ArrayList的最大容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
/**
* Returns the element at the specified position in this list.
*
获取指定元素位置的元素
*/
public E get(int index) {
//检查是否越界
rangeCheck(index);
//返回指定元素
return elementData(index);
}
}
总结
ArrayList
内部使用的是数组存储元素,当数组长度不够进行扩容的时候,每次加一半的空间,ArrayList
不会进行缩容。ArrayList
支持随机访问,通过索引访问元素极快、删除元素极快,但是删除中间元素比较慢,添加元素到中间也比较慢。ArrayList
支持求并集、交集、单向差集。