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

news2024/10/5 6:34:56

文章目录

    • Java简单集合
      • ArrayList
      • 继承体系
      • 源码解析
    • 总结

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

Java简单集合

ArrayList

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

继承体系

image-20240604155750153

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支持求并集、交集、单向差集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1792926.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++题解】1090 - 同因查找

问题&#xff1a;1090 - 同因查找 类型&#xff1a;for循环、简单循环 题目描述&#xff1a; 求出 10 至 1000 之内能同时被2、3、7 整除的数&#xff0c;并输出。 每行一个。 输入&#xff1a; 无。 输出&#xff1a; 按要求输出满足条件的数&#xff0c;每行 1 个。 完…

TiDB-从0到1-配置篇

TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCCTiDB-从0到1-部署篇TiDB-从0到1-配置篇 一、系统配置 TiDB的配置分为系统配置和集群配置两种。 其中系统配置对应TiDB Server&#xff08;不包含TiKV和PD的参数&#xff0…

GaussDB技术解读——GaussDB架构介绍(一)

目录 1 GaussDB 关键架构目标 2 GaussDB分布式架构 2.1 GaussDB 分布式关键技术架构 3 数据计算路由层&#xff08;Coordinator&#xff09;关键技术方案 3.1 分布式优化器 3.2 分布式执行框架 GaussDB是华为自主创新研发的关系型数据库&#xff0c;基于华为在数据库领域…

vivo手机如何改ip地址

在数字化时代&#xff0c;网络已成为我们日常生活和工作中不可或缺的一部分。而IP地址&#xff0c;作为网络连接的唯一标识&#xff0c;有时出于安全或隐私的需要&#xff0c;我们可能希望对其进行更改。对于使用vivo手机的用户来说&#xff0c;如何轻松修改IP地址可能是一个令…

2024后端服务架构升级

文章目录 背景改造方案新架构图技术选型思考 服务拆分公共组件设计自部署算法服务排期计划 全球多活改造背景架构图分布式ID大表分区处理范围使用用途改造方案排期计划升级预算 背景 1、xx业务经过多轮的业务决策和调整&#xff0c;存在非常多技术包袱&#xff0c;带了不好的用…

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:轨道交通监控系统

株洲中车时代电气股份有限公司&#xff08;下称中车时代电气&#xff09;是中国中车旗下股份制企业&#xff0c;其前身及母公司——中车株洲电力机车研究所有限公司创立于1959年。中车时代电气扎根株洲&#xff0c;走好两条钢轨&#xff0c;走出两条钢轨。中车时代电气秉承“双…

Flink系列三:Flink架构、独立集群搭建及Flink on YARN模式详解

一、Flink架构 Flink 是一个分布式系统&#xff0c;需要有效分配和管理计算资源才能执行流应用程序。它集成了所有常见的集群资源管理器&#xff0c;例如Hadoop yarn&#xff0c;但也可以设置作为独立集群甚至库运行。 Flink 集群剖析 Flink 运行时由两种类型的进程组成&…

【自然语言处理】【Scaling Law】Observational Scaling Laws:跨不同模型构建Scaling Law

相关博客 【自然语言处理】【Scaling Law】Observational Scaling Laws&#xff1a;跨不同模型构建Scaling Law 【自然语言处理】【Scaling Law】语言模型物理学 第3.3部分&#xff1a;知识容量Scaling Laws 【自然语言处理】Transformer中的一种线性特征 【自然语言处理】【大…

Innodb Buffer Pool缓存机制(三)Innodb Buffer Pool内部组成

一、控制块缓存页 Buffer Pool中默认的缓存页大小和在磁盘上默认的页大小是一样的&#xff0c;都是16KB。为了更好的管理这些在Buffer Pool中的缓存页&#xff0c;InnoDB为每一个缓存页都创建了一些所谓的控制信息&#xff0c;这些控制信息包括该页所属的表空间编号、页号、缓存…

自动控制:自治系统与非自治系统的稳定性分析

自动控制&#xff1a;自治系统与非自治系统的稳定性分析 在自动控制领域&#xff0c;理解自治系统和非自治系统的区别对于分析系统稳定性至关重要。自治系统的运动方程只与系统的状态有关&#xff0c;而非自治系统的运动方程则与系统的状态和时间都有关系。本文将探讨非自治系…

SqlServer2016企业版安装

前言 好久没有知识的累积&#xff0c;最近工作上遇到新的SqlServer2016安装&#xff0c;记录一下 参考文章 SQL Server 2016软件安装包和安装教程 - 哔哩哔哩 (bilibili.com) 安装包准备 需要提前准备软件安装包如下 cn_sql_server_2016_enterprise_x64_dvd_8699450&…

3. 使用tcpdump抓取rdma数据包

系列文章 第1章 多机多卡运行nccl-tests 和channel获取第2章 多机多卡nccl-tests 对比分析第3章 使用tcpdump抓取rdma数据包 目录 系列文章一、准备工作1. 源码编译tcpdump2. 安装wireshark 二、Tcpdump抓包三、Wireshark分析 一、准备工作 1. 源码编译tcpdump 使用 tcpdump…

动物收容所

题目链接 动物收容所 题目描述 注意点 若没有可以收养的动物&#xff0c;则返回[-1,-1]收纳所的最大容量为20000编号随着收养动物的增加自增 解答思路 利用队列先进先出的特点将猫和狗分别存进两个队列中&#xff0c;关键是dequeueAny这个方法中如果此时猫和狗的队列中都有…

【算法无用系列】电影推荐——余弦相似度计算用户相似度原理

【算法无用系列】通过余弦相似度计算电影、用户相似度 话不多说&#xff0c;本文通过电影推荐系统中&#xff0c;基于余弦相似度算法计算出用户相似和电影相似原理。希望可以帮助一些代码不懂的同学一些思路。 记录用户电影评分数据 一般情况来说&#xff0c;会根据用户的行为…

安装Ubuntu桌面系统(虚拟机)

VirtualBox创建虚拟机&#xff08;为安装Ubuntu桌面系统&#xff09;-CSDN博客 虚拟机的创建方法如上链接。当虚拟机开始引导之后&#xff0c;便正式开始Ubuntu桌面版的安装过程。Ubuntu桌面版界面做得很漂亮&#xff0c;操作起来也方便&#xff0c;很适合作为入门Linux的操作…

探索安全之道 | 企业漏洞管理:从理念到行动

如今&#xff0c;网络安全已经成为了企业管理中不可或缺的一部分&#xff0c;而漏洞管理则是网络安全的重中之重。那么企业应该如何做好漏洞管理呢&#xff1f;不妨从业界标准到企业实践来一探究竟&#xff01;通过对业界标准的深入了解&#xff0c;企业可以建立起完善的漏洞管…

Java+SVNCloud+Mysql课程设计

文章目录 1、主要内容2、所需准备3、与sql访问的中间类&#xff1a;SqlMessage4、窗口界面5、main方法 1、主要内容 课程设计&#xff0c;主要通过Javas wing创建窗口&#xff0c;jdbc连接云端mysql数据库进行基本操作&#xff0c;支持随机生成数据并用动态展示数据结果。 先…

重生之 SpringBoot3 入门保姆级学习(16、函数式 Web 编程)

重生之 SpringBoot3 入门保姆级学习&#xff08;16、函数式 Web 编程&#xff09; 3.4 函数式 Web 3.4 函数式 Web 个人写过 go 类似于 go gin 框架 1、场景 场景: User RESTful - CRUD GET/user/1 获取1号用户GET/users 获取所有用户POST/user 清求体携带JSON&#xff0c;新…

Java注解使用与自定义

一、什么是注解 注解是元数据的一种形式&#xff0c;它提供有关程序的数据&#xff0c;该数据不属于程序本身。注解对其注释的代码操作没有直接影响。换句话说&#xff0c;注解携带元数据&#xff0c;并且会引入一些和元数据相关的操作&#xff0c;但不会影响被注解的代码的逻…