ArrayList无参构造添加元素源码解读
一、ArrayList无参构造add方法源码阅读
@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();arrayList.add(1);arrayList.add(12);arrayList.add(13);
}
就用这个为测试吧。
对于arrayList.add(1)
debug进去:
看到进来了这里:
1、来到Integer类方法内部
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}
对于IntegerCache.cache[i + (-IntegerCache.low)];
这里应该是将cache索引为i - IntegerCache.low的元素返回,对于cache这个数组存储的个数是2x128 = 28
也就是可以存储[-128,127]这些元素。
不信可以借助工具查看:
发现确实是这样。
2、来到ArrayList的add方法:
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;
}
size是什么?查看一下:
/*** The size of the ArrayList (the number of elements it contains).** @serial*/
private int size;
确实是大小,实锤了!!!
3、来到ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//elementData是Object[0]@1098,不知道是什么,minCapacity是1
}
4、来到calculateCapacity:
private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//defaultcapacity_empty_elementdata这里是true的。return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY=10/**DEFAULT_CAPACITY: Default initial capacity.private static final int DEFAULT_CAPACITY = 10;*/}return minCapacity;
}
返回到:
ensureExplicitCapacity - > "Explicit是明确的意思"
来到:
private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);
}
minCapacity >elementData.length成立:
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}
来到Arrays.copyof:
这里的original是一个对象吧
看到上一步是:
//类成员:transient Object[] elementData;
也就是elementData这个玩意,忍了很久了,之前一度怀疑这个是不是存储节点的数据,看看它的介绍发现果然是:
* The array buffer into which the elements of the ArrayList are stored.* The capacity of the ArrayList is the length of this array buffer. Any* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* will be expanded to DEFAULT_CAPACITY when the first element is added.翻译下:* 存储 ArrayList 元素的数组缓冲区。* 数组列表的容量是此数组缓冲区的长度。任何* 空的数组列表与元素数据 == DEFAULTCAPACITY_EMPTY_ELEMENTDATA* 将在添加第一个元素时扩展到 DEFAULT_CAPACITY。
那么就继续copyof这个方法:
public static <T> T[] copyOf(T[] original, int newLength) {return (T[]) copyOf(original, newLength, original.getClass());
}
首先,分析一下这个类,返回的是一个T泛型类,那么也就是和elementData同一个类型的对象。
来到:
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")T[] copy = ((Object)newType == (Object)Object[].class)? (T[]) new Object[newLength]: (T[]) Array.newInstance(newType.getComponentType(), newLength);System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;
}
应该是走(Object)newType == (Object)Object[].class
是true,于是走这边(T[]) new Object[newLength]
了,然后再来到:
System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
这里很明显是将original的这里的内容拷贝到新的对象copy这个对象里了
,然后再返回新对象给:
public static <T> T[] copyOf(T[] original, int newLength) {
再回到:
private void grow(int minCapacity) {
返回copy给elementData.
再回到ArrayList的这个方法把里面的grow方法执行完再结束:
private void ensureExplicitCapacity(int minCapacity) {
结束。
再回到:
private void ensureCapacityInternal(int minCapacity) {
再回到add方法将最后2行执行完就结束:
public boolean add(E e) {ensureCapacityInternal(size + 1); // Increments modCount!!elementData[size++] = e;return true;
}
二、回顾:
第一步先去确认下容器大小怎么样。
如果是第一次add,就给10个容量。人哈就去扩容也就是grow方法。
这里的grow是怎么扩容呢?
看看源码:
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)//如果比MAX_ARRAY_SIZE这个都大,那么就去newCapacity = hugeCapacity(minCapacity);//获取更大的容量// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}
这里就是先按照增加原来的一半容量吧。从int newCapacity = oldCapacity + (oldCapacity >> 1)
可以看出。>>
这个符号就是有符号右移嘛,也就是除以2。
总结一下:
对于无参构造创建的ArrayList,一开始容器大小也就是size = 0,当要添加元素时,便是第一次添加元素,会扩容10个大小。后面继续添加元素时每次都会和之前的容量大小比较一下,刚好不够了再扩容,扩大50%。
先做数据的迁移,再做数据的添加。
如果是第二次扩容1,那么就是添加第11个元素时,先去grow一下,新创建数组大小为15的copy(也就是扩容),然后迁移数据。然后再将copy返回给elementData,再进行add,将元素添加到已经扩容了的elementData的末尾,可以使用这个来查看一下:
@Test//无参构造源码阅读
public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList = new ArrayList<>();ArrayList<Integer> list = new ArrayList<>();for (int i = 0; i <20; i++) {arrayList.add(i);}
}
过程和本文讲解的是一样的。
end
相关文章:

ArrayList无参构造添加元素源码解读
一、ArrayList无参构造add方法源码阅读 Test//无参构造源码阅读 public void testArrayListNoConstructorAdd(){ArrayList<Integer> arrayList new ArrayList<>();ArrayList<Integer> list new ArrayList<>();arrayList.add(1);arrayList.add(12);a…...

手写简易 Spring(二)
文章目录手写简易 Spring(二)1. 扩展 BeanFactory 接口2. 实现资源加载器,从 Spring.xml 解析和注册 Bean 对象1. 核心实现类 XmlBeanDefinitionReader3. 实现应用上下文,自动识别、资源加载、扩展机制1. 应用上下文2. 核心实现类…...
排列问题DFS入门
1、题目描述(全排列) 输入一个正整数n,输出1~n的全排列。 输入格式 一个正整数n。 输出格式 所有1~n的全排列,每个排列占一行。 样例输入 3 样例输出 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 算法思路 题目要求输出n的全…...
【每日一题Day159】LC1638统计只差一个字符的子串数目 | 枚举
统计只差一个字符的子串数目【LC1638】 给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换 一个不同字符 以后,是 t 串的子串。换言之,请你找到 s 和 t 串中 恰好 只有一个字符不同的子字符串对的数目。 比…...

【07 Metadata and VendorTag】
1. Metadata结构及分类 一个 metadata 通过tag,value及 type 来描述。不同的 metadata 分成三类 controls,dynamic 及 static 2. MTK Metadata IMetadata Mtk metadata containerIMetadataConverter Provide mutual conversion for Android camera_metadata and MTK Imetada…...

Golang中Model的使用
导语我们都知道在Golang中我们一般都是设置GOPATH目录,这个目录主要存放我们的第三方包,这个方式一直不是很方便,今天给大家介绍Go 1.11版本中推出的GoModul使用方法,学过java的同学,可能对maven包有所了解,…...

交友项目【基础环境搭建】
目录 1:交友项目架构介绍 1.1:前后端分离的概述 1.2:YAPI介绍(虚拟机中已经配好) 基本信息 使用 安装跨域拓展(浏览器上安装跨域处理插件) 2:虚拟机工具项目搭建 2.1࿱…...

入职时,公司要求自己带电脑,每月给100元补贴,如果不接受就不能入职!
为了节约成本,公司能做出什么事?一位网友遇到了这样的事:入职时,公司要求自己带电脑,每个月给100元补贴,如果不接受就得放弃入职,这样的公司有没有坑?有人问:连基本的公司…...

20道经典Redis面试题
20道经典Redis面试题 前言 整理了20道经典Redis面试题,希望对大家有帮助。 1. 什么是Redis?它主要用来什么的? Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用A…...

十分钟带你看懂接口测试,2023最全超大型接口测试攻略
一、什么是接口测试? 所谓接口,是指同一个系统中模块与模块间的数据传递接口、前后端交互、跨系统跨平台跨数据库的对接。而接口测试,则是通过接口的不同情况下的输入,去对比输出,看看是否满足接口规范所规定的功能、…...

【设计模式】创建型-单例模式
文章目录一、单例模式二、单例模式的八种实现方式2.1、饿汉式(静态常量)2.2、饿汉式(静态代码块)2.3、懒汉式(线程不安全)2.4、懒汉式(线程安全,同步方法)2.5、双重检查2…...

Python 练习 六
1、(最大数的出现)编写程序读取整数,找出它们中的最大值,然后计算它的出现次数。假设输入以数字0结束。假设你输入的是“352555 0";程序找出的最大数是5,而5的出现次数是4。(提示:维护两个变量max和 count。变量max存储的是当前最大数,而…...
「SQL面试题库」 No_22 员工奖金
🍅 1、专栏介绍 「SQL面试题库」是由 不是西红柿 发起,全员免费参与的SQL学习活动。我每天发布1道SQL面试真题,从简单到困难,涵盖所有SQL知识点,我敢保证只要做完这100道题,不仅能轻松搞定面试࿰…...

瞒不住了,Prefetch 就是一个大谎言
本文正在参加「金石计划」 Prefetch 是一个谎言 我们知道,现在的应用程序已经发展到可以拆分为多个 JavaScript包了,为了获得更好的用户体验,这些 bundle 包通常需要预获取,即 prefetch! 但是现在的prefetch 效果有多糟糕我想你…...

这个时候了,你还不会不知道JavaMail API吧
一、概述 1.1 简述 JavaMail API 顾名思义,提供给开发者处理电子邮件相关的编程接口,它是Sun发布的用来处理email的API,其提供独立于平台且与协议无关的框架来构建邮件和消息传递应用。JavaMail API 提供了一组抽象类,用于定义组…...
JavaScript var let区别
文章目录JavaScript var & let区别变量作用域变量提升变量重复声明全局对象属性for循环中的作用域JavaScript var & let区别 var和let都是用来声明变量的关键字。 变量作用域 var声明的变量作用域是函数作用域或全局作用域,而let声明的变量作用域是块级作…...
Thinkphp 6.0容器和依赖注入
本节课我们来学习一下依赖注入的用法,以及容器的用法。 一.依赖注入 1. 手册对依赖注入比较严谨的说明,具体如下: 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作 方法中一旦对参…...
Type javax.servlet.http.HttpServletRequest not present
运行环境 Swagger 3.0.0、springboot 3.0.0 产生原因: Swagger 3.0.0不支持spring3.0.0 两个解决方案: 1.降低springboot版本为2.x 2.放弃Swagger,使用 springdoc-openapi-starter-webmvc-ui 第二种解决方案: <dependen…...
一键配置Ubuntu的OpenHarmony基础编译环境
一键配置Ubuntu的OpenHarmony基础编译环境 一、配置前说明 该更新源仅适用于Ubuntu以下系列 Ubuntu18.04 Ubuntu20.04 Ubuntu22.04 强烈推荐Ubuntu20.04,本人使用的一直都是Ubuntu20.04 wsl的配置参见 如果使用的window wsl安装,则关于wsl配置可参考&a…...

ASP网络求职招聘系统的设计与实现
本文主要介绍了ASP,数据库等相关知识,同时较为详尽的阐述了网络求职招聘系统的实现。本系统是使用基于HTML语言,嵌套JavaScript源代码的ASP编程技术来开发,并以IIS为服务平台实现网络求职招聘系统的构建。后台数据库选用的是ACCES…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...

《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...

DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...