大家好哈,欢迎来到令狐小哥本期专栏,这期专栏主要是带着大家阅读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
支持求并集、交集、单向差集。