《令狐带你阅读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支持求并集、交集、单向差集。
相关推荐
哎呦没23 分钟前
SpringBoot框架下的资产管理自动化
java·spring boot·后端
m0_571957582 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
一点媛艺3 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风3 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生4 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功4 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2344 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨4 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程5 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk6 小时前
Go-性能调优实战案例
开发语言·后端·golang