深入解析 ArrayList 源码:从动态扩容到高效存取的秘密

全文目录:

    • 开篇语
    • 目录
    • 🌟 前言
    • 🧩 ArrayList 概述
    • 🏗️ ArrayList 的底层实现
      • 📐 构造函数详解
      • 🏗️ 数组的动态扩容机制
    • ⚙️ 核心方法源码解析
      • ➕ `add()` 方法的实现
      • ➖ `remove()` 方法的实现
      • 🔍 `get()` 和 `set()` 方法
    • 🌱 ArrayList 的优缺点分析
      • 优点
      • 缺点
    • 🧠 ArrayList 的适用场景
    • 📝 结语
    • 文末

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

目录

  • 🌟 前言
  • 🧩 ArrayList 概述
  • 🏗️ ArrayList 的底层实现
    • 📐 构造函数详解
    • 🏗️ 数组的动态扩容机制
  • ⚙️ 核心方法源码解析
    • add() 方法的实现
    • remove() 方法的实现
    • 🔍 get()set() 方法
  • 🌱 ArrayList 的优缺点分析
  • 🧠 ArrayList 的适用场景
  • 📝 结语

🌟 前言

嗨,Java 的小伙伴们!提到集合类,你会想到什么?相信很多人脱口而出的就是 ArrayList。作为 Java 集合框架中的明星,ArrayList 因其简单易用、存取效率高、可动态扩容等特点,成为我们开发中常用的数据结构之一。可是,背后的实现到底如何?今天我们就带着好奇心,深入挖掘 ArrayList 源码,解锁它“魔法”般高效的秘密。


🧩 ArrayList 概述

在正式进入源码解析之前,先来个快速回顾。ArrayListList 接口的实现类,本质上是一个基于动态数组的数据结构。它在内存中分配一块连续的空间,用于存储对象引用。当存储元素超过初始容量时,会自动扩容。这种机制使得它可以高效地支持随机存取和动态调整大小,非常适合于大多数需要频繁访问和追加元素的场景。


🏗️ ArrayList 的底层实现

📐 构造函数详解

ArrayList 提供了三个构造函数,我们逐个来看:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
    }
}

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
  • 无参构造函数:默认初始化一个空数组,等到添加元素时才扩展到默认容量。
  • 指定初始容量的构造函数:允许用户指定初始容量,避免频繁扩容导致的性能开销。
  • 集合构造函数:使用现有集合创建 ArrayList,便于将其他集合转为 ArrayList

🏗️ 数组的动态扩容机制

ArrayList 的关键特性就是“自动扩容”。当现有的数组空间不足以容纳新元素时,它会自动增加容量。默认情况下,每次扩容都会把数组大小增加为原来的 1.5 倍(即 newCapacity = oldCapacity + (oldCapacity >> 1))。

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容为1.5倍
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

这样做的好处是减少了数组扩容的次数,提升了性能。不过,扩容过程会涉及数组复制操作,因此在频繁增加大量元素的场景下,合理设置初始容量尤为重要。


⚙️ 核心方法源码解析

add() 方法的实现

ArrayListadd() 方法用于向集合中追加元素。它会先判断容量是否够用,如果不够用,就会调用 grow() 方法扩容。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 确保容量足够
    elementData[size++] = e;
    return true;
}

这里可以看到,add() 方法的逻辑非常简洁清晰。检查容量后,将元素存入 elementData 数组,随后更新 size 大小。

remove() 方法的实现

remove() 方法用于删除指定索引的元素。移除操作会造成元素“空洞”,所以 ArrayList 会将删除位置之后的元素向前移动,填补空缺。

public E remove(int index) {
    rangeCheck(index);
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[--size] = null;
    return oldValue;
}

从上面可以看出,remove() 方法的效率在删除末尾元素时较高,因为无需数组拷贝。然而,当删除位置较靠前时,移位操作的开销就会增大。对于这种情况,可以考虑 LinkedList 等链表结构。

🔍 get()set() 方法

get()set() 方法是 ArrayList 的读写操作,基于索引快速访问元素,非常高效。

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

public E set(int index, E element) {
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

get() 方法通过索引直接定位到对应的元素,这也是 ArrayList 的优势之一。


🌱 ArrayList 的优缺点分析

优点

  1. 快速随机访问:基于数组实现,可以通过索引高效地访问元素。
  2. 动态扩容:容量不足时自动扩展,避免手动管理数组大小。
  3. 实现简洁ArrayList 的大部分操作都很直接,适合大部分场景。

缺点

  1. 插入和删除性能较低:尤其是在头部和中间位置操作时,可能需要大量移位操作。
  2. 内存浪费:扩容机制可能导致内存浪费,特别是数据量波动较大的情况下。

🧠 ArrayList 的适用场景

根据 ArrayList 的特点,它适合以下应用场景:

  • 需要快速随机访问的场景,例如通过索引频繁获取数据的应用。
  • 数据量较小且变化不大的集合。
  • 追加读取操作频繁的应用,但不适合在中间位置频繁插入或删除的情况。

📝 结语

ArrayList 的源码实现展现了 Java 集合框架的设计之美。从构造函数到核心方法,我们看到了一个基于数组的动态数据结构如何通过扩容、移位等操作,平衡了效率和易用性。在实际开发中,选择集合类型时可以根据具体场景的需求来判断 ArrayList 是否为最佳选择。希望通过这篇解析,你能更加得心应手地使用 ArrayList,更深入地理解 Java 集合框架的实现原理!

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

排序算法之冒泡排序篇

冒泡排序的思想&#xff1a; 是一个把元素从小到大排的一个算法思想 相邻的两个元素两两比较&#xff0c;大的那一个元素向后移&#xff0c;小的那个元素向前移 核心逻辑&#xff1a; 比较所有相邻的两个项&#xff0c;如果第一个比第二个大&#xff0c;就交换它们 从头开始…

Java ArrayList 与顺序表:在编程海洋中把握数据结构的关键之锚

我的个人主页 我的专栏&#xff1a;Java-数据结构&#xff0c;希望能帮助到大家&#xff01;&#xff01;&#xff01;点赞❤ 收藏❤ 前言&#xff1a;在 Java编程的广袤世界里&#xff0c;数据结构犹如精巧的建筑蓝图&#xff0c;决定着程序在数据处理与存储时的效率、灵活性以…

【笔记】自动驾驶预测与决策规划_Part8_数据驱动的规划方法

文章目录 0. 前言1.生成模型1.1 Diffusion-ES1. Diffusion-ES算法介绍2. Diffusion-ES算法具体流程Diffusion Model 是什么&#xff1f;Diffusion-ES: Evolutionary StrategiesDiffusion-ES MethodDiffusion-ES Mapping Language instructions to reward functions with LLM pr…

React中事件处理和合成事件:理解与使用

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)

14.1 命令请求的执行过程 一个命令请求从发送到获得回复的过程中&#xff0c;客户端和服务器都需要完成一系列操作。 14.1.1 发送命令请求 当用户在客户端中输入一个命令请求的时候&#xff0c;客户端会把这个命令请求转换为协议格式&#xff0c;然后通过连接到服务器的套接字…

【C语言】字符串左旋的三种解题方法详细分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;方法一&#xff1a;逐字符移动法&#x1f4af;方法二&#xff1a;使用辅助空间法&#x1f4af;方法三&#xff1a;三次反转法&#x1f4af;方法对…

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…

零基础学安全--云技术基础

目录 学习连接 前言 云技术历史 云服务 公有云服务商 云分类 基础设施即服务&#xff08;IaaS&#xff09; 平台即服务&#xff08;PaaS&#xff09; 软件即服务&#xff08;SaaS&#xff09; 云架构 虚拟化 容器 云架构设计 组件选择 基础设施即代码 集成部署…

【Linux】网络通信

TCP协议是一个安全的、面向连接的、流式传输协议&#xff0c;所谓的面向连接就是三次握手&#xff0c;对于程序猿来说只需要在客户端调用connect()函数&#xff0c;三次握手就自动进行了。先通过下图看一下TCP协议的格式&#xff0c;然后再介绍三次握手的具体流程。 TCP的三次握…

Pgsql:json字段查询与更新

1.查询json字段的值 SELECT attribute_data->>设施类别 mycol, * FROM gis_coord_data WHERE attribute_data->>设施类别阀门井 查询结果如下&#xff1a; 2.更新json字段中的某个属性值 UPDATE gis_coord_data SET attribute_data(attribute_data::jsonb ||{&quo…

对于GC方面,在使用Elasticsearch时要注意什么?

大家好&#xff0c;我是锋哥。今天分享关于【对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f;】面试题。希望对大家有帮助&#xff1b; 对于GC方面&#xff0c;在使用Elasticsearch时要注意什么&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java…

基于Netty实现聊天室

前言 了解了Netty的基本功能和相关概念&#xff0c;使用基于Netty实现多人聊天的功能。 需求 1.服务端能够接收客户端的注册&#xff0c;并且接受用户的信息注册 2.服务端能够处理客户端发送的消息&#xff0c;并且根据消息类型进行私发或者广播发送消 3.服务端能够私发消…

Linux -日志 | 线程池 | 线程安全 | 死锁

文章目录 1.日志1.1日志介绍1.2策略模式1.3实现日志类 2.线程池2.1线程池介绍2.2线程池的应用场景2.3线程池的设计2.4代码实现2.5修改为单例模式 3.线程安全和函数重入问题3.1线程安全和函数重入的概念3.2总结 4.死锁4.1什么是死锁4.2产生死锁的必要条件4.3避免死锁 1.日志 1.…

【博主推荐】C#的winfrom应用中datagridview常见问题及解决方案汇总

文章目录 1.datagridview绘制出现鼠标悬浮数据变空白2.datagridview在每列前动态添加序号2.1 加载数据集完成后绘制序号2.2 RowPostPaint事件绘制 3.datagridview改变行样式4.datagridview后台修改指定列数据5.datagridview固定某个列宽6.datagridview某个列的显示隐藏7.datagr…

【设计模式】创建型模式之单例模式(饿汉式 懒汉式 Golang实现)

定义 一个类只允许创建一个对象或实例&#xff0c;而且自行实例化并向整个系统提供该实例&#xff0c;这个类就是一个单例类&#xff0c;它提供全局访问的方法。这种设计模式叫单例设计模式&#xff0c;简称单例模式。 单例模式的要点&#xff1a; 某个类只能有一个实例必须…

Vivado程序固化到Flash

在上板调试FPGA时&#xff0c;通常使用JTAG接口下载程序到FPGA芯片中&#xff0c;FPGA本身是基于RAM工艺的器件&#xff0c;因此掉电后会丢失芯片内的程序&#xff0c;需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序&#xff0c;一般FPGA的外围会…

技术文档,they are my collection!

工作 今天这篇文章&#xff0c;献给一直撰写技术文档的自己。我自认为是公司中最爱写文档的人了&#xff0c;我们是一个不到40人的小公司&#xff0c;公司作风没有多么严谨&#xff0c;领导也不会要求我们写技术文档。但是从入职初至今&#xff0c;我一直保持着写技术文档…

微信小程序学习指南从入门到精通

&#x1f5fd;微信小程序学习指南从入门到精通&#x1f5fd; &#x1f51d;微信小程序学习指南从入门到精通&#x1f51d;✍前言✍&#x1f4bb;微信小程序学习指南前言&#x1f4bb;一、&#x1f680;文章列表&#x1f680;二、&#x1f52f;教程文章的好处&#x1f52f;1. ✅…

JavaWeb——SpringBoot原理

10.1. 配置优先级 10.1.1. 配置文件 properties > yml(推荐) > yaml 10.1.2. Java系统属性、命令行参数 命令行参数 > Java系统属性 > 配置文件 10.2. Bean管理 10.2.1. 手动获取bean ApplicationContext&#xff0c;IOC容器对象 10.2.2. bean作用域 10.2.3.…

如何在Python中进行数学建模?

数学建模是数据科学中使用的强大工具&#xff0c;通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统&#xff0c;为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程&#xff0c;重点关注数据科学中的应用。 数学建…