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

简介: 《令狐带你阅读JDK源码之简单集合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支持求并集、交集、单向差集。
目录
相关文章
|
监控 关系型数据库 MySQL
MySQL 5.7在高并发下性能劣化问题的详细剖析
TL;DR MySQL 5.7高并发读写混合场景下rt飙升,业务系统大量超时报错。本文总结了阿里业务场景下遇到的坑,剖析问题背后的原因,帮助读者更好的理解MySQL内核原理,降低升级MySQL 5.7的风险。
10130 0
|
8月前
|
算法 搜索推荐 大数据
数据驱动增长:大数据与营销自动化的结合之道
数据驱动增长:大数据与营销自动化的结合之道
192 3
|
Linux 虚拟化 数据中心
在Linux中,如何进行系统资源的隔离?
在Linux中,如何进行系统资源的隔离?
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的二手图书交易系统的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的二手图书交易系统的详细设计和实现(源码+lw+部署文档+讲解等)
204 4
|
12月前
|
前端开发
「Mac畅玩鸿蒙与硬件49」UI互动应用篇26 - 数字填色游戏
本篇教程将带你实现一个数字填色小游戏,通过简单的交互逻辑,学习如何使用鸿蒙开发组件创建趣味性强的应用。
305 20
「Mac畅玩鸿蒙与硬件49」UI互动应用篇26 - 数字填色游戏
|
机器学习/深度学习 数据采集 人工智能
基于Huffman树的层次化Softmax:面向大规模神经网络的高效概率计算方法
层次化Softmax算法通过引入Huffman树结构,将传统Softmax的计算复杂度从线性降至对数级别,显著提升了大规模词汇表的训练效率。该算法不仅优化了计算效率,还在处理大规模离散分布问题上提供了新的思路。文章详细介绍了Huffman树的构建、节点编码、概率计算及基于Gensim的实现方法,并讨论了工程实现中的优化策略与应用实践。
289 15
基于Huffman树的层次化Softmax:面向大规模神经网络的高效概率计算方法
|
Docker 容器
docker安装minio
以上就是在Docker中安装MinIO的步骤。
673 2
|
SQL 安全 数据库
|
机器学习/深度学习 自然语言处理 PyTorch
自然语言处理实战第二版(MEAP)(五)(1)
自然语言处理实战第二版(MEAP)(五)
149 1
|
Ubuntu Docker 容器
迁移harbor
在Ubuntu 22.04 LTS环境中,已安装Docker的Harbor从v2.5.3迁移到v2.9.0,保留原有镜像数据。参考官方文档[v2.9.0](https://goharbor.io/docs/2.9.0/),执行包括数据目录复制、解压新版本、配置harbor.yml和docker-compose.yml、运行安装脚本等步骤。迁移后,通过测试推拉镜像确保功能正常。注意查看潜在的部署问题。
393 0