《令狐带你阅读JDK源码之简单集合ArrayList》

文章目录

大家好哈,欢迎来到令狐小哥本期专栏,这期专栏主要是带着大家阅读JDK源码,我会分几期篇幅来介绍这个jdk源码、会进行剖析、梳理,欢迎大家指正阅读。后面我会配套自己的视频进行讲解~

Java简单集合

ArrayList

ArrayList是一种以数组实现的List,与数组相比,它具有动态扩展的能力,因此又被称为:动态数组。

继承体系

ArrayList实现了List,Serializable,RandomAccess,Cloneable

  • ArrayList实现了List,提供了基础的添加,删除,遍历等操作。
  • ArrayList实现了Serializable,表示可以被序列化。
  • ArrayList实现了 Cloneable,可以被克隆。
  • ArrayList实现了RandomAccess,提供了随机访问的能力。

源码解析

java 复制代码
/**
 * @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支持求并集、交集、单向差集。
相关推荐
逝水如流年轻往返染尘10 分钟前
JAVA中的抽象类
java·开发语言
困死,根本不会17 分钟前
【C 语言】指针学习笔记:从底层原理到实战应用
c语言·开发语言·笔记·学习·算法
自动化和Linux31 分钟前
C语言_scanf(),strlen(),size()的特性和各自的区别
c语言·开发语言
hx8622736 分钟前
Java MySQL 连接
java·mysql·adb
lpfasd12338 分钟前
Kubernetes (K8s) 底层早已不再直接使用 Docker 引擎了
java·docker·kubernetes
aq553560041 分钟前
SpringBoot有几种获取Request对象的方法
java·spring boot·后端
小郝 小郝1 小时前
51 与32 单片机LED控制详解
c语言·开发语言·经验分享·学习·51单片机
星空露珠1 小时前
迷你世界UGC3.0脚本Wiki全局函数
开发语言·数据库·算法·游戏·lua
金山几座1 小时前
C#学习记录-类(Class)
开发语言·学习·c#
AsDuang1 小时前
Python 3.12 MagicMethods - 55 - __irshift__
开发语言·python