JAVA_ArrayList添加元素时的源码分析(jdk17)

news2024/11/18 4:24:31

目录

ArrayList 在 Collection 中的位置:

ArrayList 集合底层原理:

先总结:

ArrayList 底层是数组结构的:查找快,增删慢

看源码:

看一些重要的源码:

第一次存元素:

逻辑总览图:

长度为 10 的底层数组存满后继续存:

逻辑总览图:


ArrayList 在 Collection 中的位置:

因为 ArrayList 是 List 接口和 Collection 接口的实现类,所以它们的方法 ArrayList 也可以用。


ArrayList 集合底层原理:

先总结:

ArrayList 底层是数组结构的:查找快,增删慢

  1. 利用空参创建的集合,在底层会创建一个默认长度为 0 的数组(数组名: elementData)。
  2. 添加第一个元素时,底层会创建一个新的长度为 10 的数组
  3. 存满时,若再添加元素,数组会扩容 1.5 倍。
  4. 如果一次添加多个元素,1.5 倍还放不下,则新创建数组的长度以实际为准,(也就是说 当添加元素个数超过了原来长度的一半时,就会以实际添加量为准进行扩容
    1. 如图:


先看一些重要的源码:

1.首先找到 ArrayList-->Alt+7 看大纲 --> 找到空参构造

2.看到一个叫 "默认长度 _ 空 _元素数据" 赋值给了 “元素数据”

3.发现了 这个 "默认长度 _ 空 _元素数据" 的东西 其实是一个长度为 0 的数组

4.所以当空参创建集合对象时,此时集合元素的数量是 0


开始分析:

第一次存元素:

假设我们使用空参创建了一个集合,

并要添加一个元素“aaa”

1. 首先 add 方法接收参数,

并且 modCount++,表示集合操作次数加 1,

接着调用另一个 add 方法:

    • 第一个参数是“aaa”
    • 第二个参数是那个在创建集合时就已经创建好的的底层数组 elementDate
    • 第三个参数是集合的长度,为 0

2.add 中的 add 方法:

因为 size 此时为 0,数组长度也为 0 所以进入 if 语句调用 grow()方法进行扩容

3.接着来看 grow 源码:

在 grow 内也调用了一个 grow 方法,并传入参数 1,

表示添加完当前元素之后的最小容量

4.grow 中的 grow 源码:

1 赋值给了 minCapacity

数组的长度到目前为止,没发生过变化,为 0

不满足 if 条件直接跳过,第一次添加数据的时候,会执行到else这里,

若在以后继续添加元素,就会执行 if 里面的代码

else 内将minCapacity 和DEFAULT_CAPACITY 进行了比较,看看DEFAULT_CAPACITY 内是什么

最后第二个 grow 方法原路返回一个长度为10的新数组

5. 最后:

元素"aaa"放入底层新数组的 0 索引处,集合长度 size 变为 0+1=1。

逻辑总览图:


长度为 10 的底层数组存满后继续存:

现在假设之前底层创建的默认长度为 10 的数组已被存满了,

这时再存一个元素"aaa",看看底层逻辑是怎样的:

第一步还是看 add 方法:

首先 add 方法接收参数"aaa",

并且 modCount++,集合操作次数加 1,

接着调用另一个 add 方法:

    • 第一个参数是“aaa”
    • 第二个参数是 那个 存满 10 个元素的底层数组 elementDate
    • 第三个参数是 集合的长度,为 10

2.add 中的 add 方法:

因为 size 此时为 10,数组长度也为 10, 所以进入 if 语句调用

grow()方法进行扩容:

3.现在看 grow 方法:

发现在 grow 内也调用了一个 grow 方法,并传入参数 11,

表示添加完当前元素之后的最小容量

4.grow 中的 grow 源码:

11 赋值给了 minCapacity

数组的长度到目前为止,没发生过变化,为 10,赋值给了old capacity 记录为老容量。

此时满足 if 条件(若是第一次存元素不会走 if),

在 if 内调用了一个Arrays Support 的 new Length 方法,并且传递了三个参数:

1.老容量

2. 理论增长容量 1,

3. 默认实际增长量是oldcapacity 进行右位移 1 的结果(10/21=5)。

我们来看看 newLength 方法:

(有个细节:这里为什么要将 minGrowth 和 preGrowth 进行比较

因为考虑到了一次添加多个元素的情况,如添加了一个长度为 100 的集合,这里的 minGrowth 就会是 100,经过比较最后取得增长量才会是 100,也就是说当添加元素个数超过了原来长度的一半时,就会以实际添加量为准进行扩容)

扩容后的长度用 preLength 接收,后面的 if 先不用看。

然后将扩容后的长度preLength =15 返回第二个 grow 方法的newCapacity 变量

然后调用了 Arrays 的 copyOf 方法:

根据长度 newCapacity :15创建新的数组

并把老数组中的所有数据全部拷贝到这个长度为 15 的新数组当中

最后将该数组原路返回

5.最后:

元素"aaa"放入底层新数组的 10 索引处,size 变为 10+1=11。

逻辑总览图:

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

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

相关文章

C++ STL之queue的使用及模拟实现

文章目录 1. 介绍2. 队列的使用3. 队列的模拟实现 1. 介绍 英文解释: 也就是说: 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。 队列作为容器适配器实现&…

go语言(十七)----json

1、结构体转json package mainimport ("encoding/json""fmt" )type Movie struct{Title string json:"title"Year int json:"year"Price int json:"rmb"Actors []string json:"actors" }func main() {movie : Mo…

数字与数学高频问题(算法村第十三关白银挑战)

数组实现加法专题 数组实现整数加法 66. 加一 - 力扣(LeetCode) 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数…

【刷题】 leetcode 面试题 01.06 字符串压缩

字符串压缩 字符串压缩思路一(双指针顺畅版)思路二(sprintf函数巧解版) Thanks♪(・ω・)ノ谢谢阅读下一篇文章见!!! 字符串压缩 来看题目: 根据题目…

OpenCV第 2 课 OpenCV 环境搭建

文章目录 第 2 课 OpenCV 环境搭建1.安装 Numpy2.从 Ubuntu 存储库安装 OpenCV3.验证 OpenCV 安装 第 2 课 OpenCV 环境搭建 1.安装 Numpy 每一张图像都有很多个像素点,这也导致了程序中会涉及大量的数组处理。Numpy 是一个 Python 的拓展库,它对多维数…

Linux环境docker安装Neo4j,以及Neo4j新手入门教学(超详细版本)

目录 1、 图数据库Neo4j简介1.1 什么是图数据库1.2 能解决什么痛点1.3 对比关系型数据库1.4 什么是Neo4j1.5 Neo4j的构建元素 2. 环境搭建2.1 安装Neo4j Community Server2.2 docker 安装Neo4j Community Server2.3 Neo4j Desktop安装 3. Neo4j - CQL使用3.1 Neo4j - CQL简介3.…

C++模板与STL【常用算法】

🌈个人主页:godspeed_lucip 🔥 系列专栏:C从基础到进阶 🎄1 STL常用算法🏆1.1 常用遍历算法🍉1.1.1 for_each🍉1.1.2 transform 🏆1.2 常用查找算法🍋1.2.1 f…

STL第二讲

第二讲 视频标准库源码版本:gnu c 2.9.1/4.9/Visual C OOP vs GP GP是将datas与methods分开,OOP相反; 为什么list不能使用全局的sort? 因为sort源代码: *(first (last - first)/2) // 此迭代器只能是随机访问迭代…

C语言快速排序(非递归)图文详解

前言: 上一期分析了快速排序的三种写法,这三种写法有一个相同点,都是采用递归形式来实现的,那么有没有非递归的方法实现呢?答案是当然有,用非递归的方法实现快速排序,其实可以借助数据结构中的栈…

C++笔记(二)

函数的默认参数 如果我们自己传入数据,就用自己的数据,如果没有,就用默认值 语法: 返回值类型 函数名(形参默认值){} int func(int a,int b20,int c30){} …

HTTP与HTTPS的工作流程

HTTP与HTTPS的工作流程 http知识点回顾1、HTTP访问的过程2、HTTP常见状态码3、HTTP 协议一共五大特点 https的工作流程1、对称加密2、非对称加密3、https工作流程 http知识点回顾 1、HTTP访问的过程 (1)解析url,获取 url 中包含的域名&…

Unity3D Pico VR 手势识别物体交互 适配 MRTK3

当前Pico已经支持手势识别了,但是提供的PICO Unity Integration SDK 中是没有手势和物体交互的功能,Unity XR Interaction Toolkit提供的手势识别物体交互对 Quest适配的挺好的,Pico 当前只能用指尖点触还不能对物体进行抓握以及手势控制射线…

仅使用 Python 创建的 Web 应用程序(前端版本)第05章_共通代码

前面介绍了很多,但是让我们从本章开始实现 WTS。 在本章中,我们将实现所有页面的公共部分:SessionManager、MockDB、Model 和 Application。 SessionManger 与 Streamlit 会话交互。 在WTS中,我们的目标是使代码清晰,SessionManager负责读写st.session_state数据。 Mock…

数据结构:3_栈和队列

栈和队列 一.栈 1. 栈的概念及结构 栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。**进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。**栈中的数据元素遵守后进先出LIFO(Last In First Out&#x…

【QML-Qt Design Studio】

QML编程指南 ■ Qt Design Studio (Qt Quick UI设计工具)■ 安装Qt Design Studio■ ■ Qt Design Studio (Qt Quick UI设计工具) Qt Design Studio是一个用于创建酷炫、优美UI的工具。 简单概括其功能就是让UI设计转换为qml&…

uniapp+vue3+ts--编写微信小程序对接e签宝签署时跳转刷脸效果(人脸识别)中间页代码

uniappvue3ts–编写微信小程序对接e签宝签署时跳转刷脸效果(人脸识别)中间页代码 e签宝内嵌H5方式集成签署页的文档说明:https://open.esign.cn/doc/opendoc/case3/ahb0sg 签署时跳转刷脸效果示意图: 1. 在文件夹新建一个文件&a…

java基础:有序数组中插入数字使其依然有序案例分析

问题目标是将用户输入的整数插入到一个已排序的数组中,以保持数组的有序性。 如何实现? 思路分析: 初始化已排序的数组:通过使用int[] arr {1, 2, 3, 4, 5, 6};语句创建一个已经排好序的数组。定义变量:index用于记…

2024年制造业展望

制造业是国民经济的主体,其重要性不言而喻。就2023年而言,制造业在技术创新、数字化转型和可持续发展方面都取得了重要的进展。以下是对于2024年制造业的发展进行的分析与预测。 1 保持业务平衡仍将是一项挑战 在过去的四年里,制造业高管人…

【IEEE会议征稿】2024年第九届智能计算与信号处理国际学术会议(ICSP 2024)

2024年第九届智能计算与信号处理国际学术会议(ICSP 2024) 2024年第八届智能计算与信号处理国际学术会议(ICSP 2024)将在西安举行, 会期是2024年4月19-21日, 为期三天, 会议由西安科技大学主办。 欢迎参会&…

Django开发_17_表单类

一、介绍 为了简化前端form表单代码 二、步骤 (一)创建form.py 创建一个表单类 from django import formsclass RegisterForm(forms.Form):reg_name forms.CharField(max_length10, label用户名)reg_pwd forms.CharField(max_length20, label密码…