ArrayList源码分析之 add 方法

quartus 13.1常见报错解决方法 在使用quartus中会遇到很多由于安装或设置不规范造成的错误。我就目前我遇到的一些错误以及我的解决方法分享给大家,这个文章将会持续更新,如果读者有遇到软件中错误无法解决的问题,也欢迎在评论区留言。 一、编译出现lience错误 在对设计的电路编译时,系统在程序运行3秒内即结束并报错,大概意思为现有的证书不支持编译。这个常见问题源自破解不成功,这里读者很有可能犯的错误是在使用破解器的时候没有区分x86(即32-bit)和x64软件破解器对应的文件夹。 如图所示有两种破解器,分别对应32位和64位的软件,大部 阅读详情

在Java编程中,常常需要集中存放多个数据,从传统意义上讲,数组是我们的一个很好的选择,前提是我们事先已经明确知道我们将要保存的对象的数量。一旦在数组初始化时指定了这个数组长度,这个数组长度就是不可变的,如果我们需要保存一个可以动态增长的数据(在编译时无法确定具体的数量),

List 这个集合类是便为我们提供了相当于动态数组的功能。这个类中add方法尤为重要。

 1 目标

本次源码分析的目标是深入了解 List类中 add 方法的实现机制。

 

2 分析方法

首先编写测试代码,然后利用 Intellij Idea 的单步调试功能,逐步的分析其实现思路。

 

测试代码如下:

List<String> mList=new ArrayList<String>(); 
mList.add("张三");//断点
mList.add("李四");
mList.add("王五");

mList.add(1,"赵六");//断点

3 分析流程

点击调试按钮,开始分析流程。

 

3.1 构造函数

首先进行的是构造函数的分析,点击 Shift+F7进入构造函数实现。

 

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

点击进入后,我们看到的是以上代码,这里疑惑就来了,这个elemendata代表什么呢?这个DEFAULTCAPACITY_EMPTY_ELEMENTDATA又是什么意思呢?

 

我们可以在定位在elemenData处按 Ctrl+B进入查看做进一步分析。

transient Object[] elementData;

通过上述代码我们知道,elemenData是一个Object型的数组。那为什么会定义成Object型的呢?我们可以想一下,如果是String,int或是其他类型的,那么存放的数据是不是就受到了限制了呢?而Object型的就能保证我们可以将任何类型的数据存放进去。可以看到,Object前面有一个transient,那这个transient是什么意思呢?

我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

同理我们来看DEFAULTCAPACITY_EMPTY_ELEMENTDATA:

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

可见这是一个Object型的常量数组,并将其赋了空值。到这里我们就能知道构造方法里是将elemenData数组初始化为空。

 

3.2 booleanadd(E  e)方法  

 

接下来我们分析add( E  e)方法的实现机制。

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
确定内部容量是否够了,size是数组中数据的个数,因为要添加一个元素,所以size+1,先判断size+1的这个个数数组能否放得下,就在这个方法中去判断数组.length是否够用了。

从上述代码可以看到,这里调用了ensureCapacityInternal方法,我们来看看其实现机制

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

由此我们可以看出这是一个确定内部容量的方法,这里我们先定位在DEFAULT_CAPACITY上Ctrl+B进去可以看到其值为10;首先判断初始化的elementData是不是空的数组,也就是没有长度因为如果是空的话,minCapacity=size+1;其实就是等于1,空的数组没有长度就存放不了,所以就将minCapacity变成10,也就是默认大小,但是在这里,还没有真正的初始化这个elementData的大小。

我们继续按F7调试下一步,将会运行ensureExplicitCapacity方法
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
minCapacity如果大于了实际elementData的长度,那么就说明elementData数组的长度不够用,不够用那么就要增加elementData的length。有的同学可能会疑惑minCapacity到底是什么呢?我们来分析一下:
1)           由于elementData初始化时是空的数组,那么第一次add的时候,minCapacity=size+1;也就minCapacity=1,在上一个方法(确定内部容量ensureCapacityInternal)就会判断出是空的数组,就会将minCapacity=10,到这一步为止,还没有改变elementData的大小。
2)           elementData不是空的数组了,那么在add的时候,minCapacity=size+1;也就是minCapacity代表着elementData中增加之后的实际数据个数,拿着它判断elementData的length是否够用,如果length不够用,那么肯定要扩大容量,不然增加的这个元素就会溢出。

F7调试下一步执行grow方法,arrayList核心的方法,能扩展数组大小的真正秘密。我们下一节详细分析该方法。

3.3 grow(int minCapacity)方法

 

按住 Shift+F7进入该方法的实现代码。

 


 
/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length; //将扩充前的elemenData大小给oldCapacity
    int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity的大小就是1.5倍的oldCapacity,相当于将elemenData之前的大小扩充为原来的1.5倍。
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
//这段代码判断将elemenData大小扩充1.5倍过后与minCapacity作比较,在§3.2节我们已经知道minCapacity默认值为10。判断成立便将minCapacity赋值给newCapacity,在这里就是真正的初始化elemenData的大小了。这段代码适应于elemenData数组为空的时候,elementData.length=0,则oldCapacity=0,newCapacity=0,所以该判断成立。
    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);
}minCapacity作比较,在§3.2节我们已经知道minCapacity默认值为10。判断成立便将minCapacity赋值给newCapacity,在这里就是真正的初始化elemenData的大小了。这段代码适应于elemenData数组为空的时候,elementData.length=0,则oldCapacity=0,newCapacity=0,所以该判断成立。
    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);
}

 

 

 


if (newCapacity- minCapacity < 0)
       
newCapacity = minCapacity;
 

 

if (newCapacity- MAX_ARRAY_SIZE > 0)
       
newCapacity = hugeCapacity(minCapacity);
//这里有个MAX_ARRAY_SIZE,可是MAX_ARRAY_SIZE代表什么呢?

按住Ctrl+B查看源码:

/**
 * 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;

根据注释我们了解到MAX_ARRAY_SIZE代表最大容量限制。所以代码含义是如果newCapacity超过了最大容量限制的话就调用hugeCapacity方法,将能给的最大值给newCapacity。hugeCapacity方法又是怎么一回事呢?我们下一节再来介绍。

 

elementData= Arrays.copyOf(elementData,newCapacity);//最后copy数组,改变数组容量。

3.4 hugeCapacity()方法

 

按住 Shift+F7进入该方法的实现。

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

 

从上述代码可以看出,hugeCapacity方法用于确定elemenData数组的最大容量。如果minCapacity > MAX_ARRAY_SIZE说明扩容时扩得过大,则返回Integer.MAX_VALUE,否则返回MAX_ARRAY_SIZE。在上一节已经说过MAX_ARRAY_SIZE的含义,那MAX_ARRAY_SIZE和Integer.MAX_VALUE的值具体又是多少呢?

按住Ctrl+B查看源码:

@Native public static final int   MAX_VALUE = 0x7fffffff;

 

3.5void add(int,E)方法

 

按住 Shift+F7进入该方法的实现代码:

/**
 * Inserts the specified element at the specified position in this
 * list. Shifts the element currently at that position (if any) and
 * any subsequent elements to the right (adds one to their indices).
 *
 * @param index index at which the specified element is to be inserted
 * @param element element to be inserted
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

 

此方法用于在特定位置将元素添加进集合,也就是插入元素。先调用rangeCheckForAdd方法检查插入的位置是否合理,然后调用ensureCapacityInternal方法将index之后的元素都往后移动一位(具体分析看上面的小节),并在目标位置上将要插入的元素存放进elemenData数组。最后数组大小加一。

 

4 总结

本文分析了List类的 add 方法,包括在末尾添加元素和在指定位置添加元素。通过分析我们知道List集合就相当于一个elemenData数组,该数组可以实现自动扩容。当我们调用add方法的时候实际上的函数调用顺序为:

后面两个方法并不是每次调用add方法时,当添加进的元素数量大于elemenData默认容量时会调用grow方法进行扩容,而当扩容过大时会调用hugeCapacity方法进行最大容量限制。

 对比一下传统的数组,在使用数组时我们需要事先固定好其大小,然而在实际开发中我们往往是不能预测究竟会存放多少数据进去的,当我们需要改变数组大小时,又要回过头开修改代码,这岂不是徒增麻烦。而List集合就避免了这种麻烦,给开发人员与维护人员提供了极大地便利,所以在实际开发中被人们广泛使用。了解其实现机制是很有意义的。

 

Qt界面美化-飞扬青云自绘控件插件的使用-避免采坑 1、先上一个集成到QtCreater中的效果图: 2、飞扬青云自绘控件插件下载地址:https://gitcode.net/mirrors/feiyangqingyun/qucsdk?utm_source=csdn_github_accelerator 3、集成插件到QtCreater中的方法: (1)、查看自己使用的QtCreater的版本信息,我的:Qt 5.15.2 MSVC2019 64位 (2)插件下载下来后工程预览: 我选择msvc版本的SDK,打开找到匹配的SDK:... 阅读详情

相关推荐

Matlab实战:12种优化算法在CEC2014测试集上的性能对比(附完整代码)

本文详细对比了12种优化算法在CEC2014测试集上的性能表现,包括PSO、DE、GA等主流算法。通过Matlab实现完整的实验流程,涵盖算法实现、参数设置、结果分析与可视化,为工程优化问题提供实用解决方案。特别关注收敛曲线和评价指标,帮助读者选择最适合特定场景的优化算法。

wine的专栏 681

数据结构思维 第二章 算法分析

第二章 算法分析 原文:Chapter 2 Analysis of Algorithms 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 我们在前面的章节中看到,Java 提供了两种实现List的接口,ArrayList和LinkedList。对于一些应用,LinkedList更快;对于其他应用,ArrayList更快。要确定对于特定的应用,

龙哥盟 4万+

AD9371 官方例程构建及单音信号收发

项目构建基本流程和AD9361差不多,由于官方使用的ZCU102,记录下移植遇到的一些问题最终接收到正确的正弦波Errors: 0Errors: 0Errors: 0Errors: 0AD9361。

weixin_44630490的博客 2973

数据结构思维 第三章 `ArrayList`

第三章 ArrayList 原文:Chapter 3 ArrayList 译者:飞龙 协议:CC BY-NC-SA 4.0 自豪地采用谷歌翻译 本章一举两得:我展示了上一个练习的解法,并展示了一种使用摊销分析来划分算法的方法。3.1 划分MyArrayList的方法对于许多方法,我们不能通过测试代码来确定增长级别。例如,这里是MyArrayList的get的实现:

龙哥盟 4万+

报错:subprocess.CalledProcessError: Command ‘[‘where‘, ‘cl‘]‘ returned non-zero exit status 1.

右键此电脑--属性--高级系统设置--环境变量--系统变量--找到Path。Enterprise是企业版,如果你是社区版就找Community。2.安装的时候,c++桌面那个需要勾选。

2301_77554343的博客 1507

FME入门系列教程3-带你玩转GIS数据搬运与处理

FME(Feature Manipulation Engine)就像GIS界的"瑞士军刀",它能轻松解决90%的数据处理难题。我最初接触FME是因为要处理200多个不同格式的CAD地形图,传统方法需要1周时间,用FME只花了2小时!:支持300+数据格式(Shapefile、GeoJSON、CAD、Excel等)添加Reader(数据源):选择示例数据roads.shp。添加Writer(输出):设置输出为GeoJSON格式。:将常用流程保存为Template(.fmwt)

weixin_41234946的博客 1244

java数组解析_Java - 数组解析

一、什么是数组数组?什么是数组?在我印象中的数组是应该这样的:通过new关键字创建并组装他们,通过使用整形索引值访问它的元素,并且它的尺寸是不可变的!但是这只是数组的最表面的东西!深一点?就是这样:数组是一个简单的复合数据类型,它是一系列有序数据的集合,它当中的每一个数据都具有相同的数据类型,我们通过数组名加上一个不会越界下标值来唯一确定数组中的元素。不管在其他语言中数组是什么,在java中它就是...

weixin_31534091的博客 709

温度实时检测预警系统(STC89C51RC+DS18B20)

温度实时检测预警系统

1 兴趣 2 实践 1495

【Java】ArrayList实现原理浅析,Java框架体系架构的知识

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } 2.1.2 指定数组容量大小参数的构造函数 指定容量>0,直接new一个指定大小的对象数组; =0,指定一个空对象数组 <0,抛异常 private static final Object[] EMPTY_

澎湖Java架构师的博客 374

快速理解STLink引脚图中复位引脚作用

深入讲解STLink引脚图中复位引脚的实际用途,帮助开发者快速掌握其在调试与下载过程中的关键作用,结合stlink引脚图理解更高效。

weixin_32324637的博客 1326

网络流量异常信息分析方法研究

本课题针对网络安全中网络流量异常的分析方法进行研究,提出一种基于机器学习和深度学习的异常检测算法。该算法采用卷积神经网络(CNN)和长短时记忆神经网络(LSTM)结合的方式,通过训练得到二分类模型,从而实现对网络流量异常的检测。随着互联网的飞速发展,网络攻击事件日益增多,网络安全问题成为了亟待解决的问题之一。常见的网络攻击手段包括 DDoS 攻击、SQL 注入、XSS 攻击等,这些攻击手段可能导致网络系统发生异常,给网络运维、数据安全带来极大的挑战。

肥晨开发的学习之路 1035

JDK类库源码分析系列3--集合类分析(1) List集合3-ArrayList

一、ArrayList的结构 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable public interface RandomAccess { } ​ 其继承的AbstractList,同时又实现RandomAccess这个算法标记接口。 二、成员变量 1、DEFAULT_

Feverasa的博客 340

我用 GPT-5.5 十分钟搞定一篇文献综述!附全流程指南

每一个框架中提出的逻辑链接,都必须至少有一篇提供文本中的文献作为支撑、严格禁止虚构变量、逻辑关系或研究结果、如果某些变量或关系在文本中未提及,必须明确声明“在提供的文本中未找到相关信息”、引用格式必须严格遵循原文提供的“作者/年份”格式,例如:[Smith, 2022]。各位同仁好,我是七哥。扫描提供的文献摘要,识别存在冲突的结果或理论、分析这些文献之间的差异,并总结可能导致差异的原因、输出一个结构化的学术争论段落,清楚呈现文献间的分歧和潜在影响因素、对于缺失或不明确的信息,按约束条件如实标注。

智能AI让学术科研更容易 370

ArrayList中add方法源码分析~

首先要明确ArrayList的底层实现是数组利用空参创建的集合时,在底层创建一个默认长度为0的数组添加第一个元素时,底层会创建一个新的长度为10的数组存满时,会扩容1.5倍如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准。

2501_90392153的博客 1904

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java8 ArrayList源码分析1->add方法和remove方法

今天在做算法题目的时候,使用到了ArrayList,在获取size想到了一个问题,在使用add操作的时候,ArrayList的源码是怎么实现的,然后我下载 了jdk1.8的源码。 首先,ArrayList的初始容量是10,无论是什么操作,首先会调用最低容量为10。最终的实现是使用了System.arrayopy方法。 如果执行add操作 ,有两种方法可供选择: 1.add(E e)方法,该方法会在ArrayList的尾部插入元素,首先会调用ensureCapacityInternal方法来检查数组的容

FanJqi的博客 596

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

ArrayList源码分析之add 方法

欢迎点击「算法与编程之美」↑关注我们!本文首发于微信公众号:"算法与编程之美",欢迎关注,及时了解更多此系列博客。在Java编程中,常常需要集中存放多个数据,从传统意...

算法与编程之美 837

ArrayList_add( ) 方法源码分析

以下为ArrayList的基础参数: /** * 默认初始容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 用于空实例的共享空数组实例 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 数组缓冲区中存储ArrayList元素的数组缓冲区...

butterBallj的博客 420

ArrayList中add方法源码分析

当我们通过ArrayList的无参构造方法创建一个ArrayList对象时,ArrayList的无参构造方法会初始化一个数组类型的elementData成员变量,该成员变量就是ArrayList具体用来存放数据的变量,由此可知ArrayList是基于数组来实现的。 当程序调用add方法向我们新建的集合类添加值的时候,添加方法会先调用ensureCapacityInternal方法,对集合容量进行确认。 ensureCapacityInternal方法用来对ArrayList进行扩...

bc_Reversing的博客 335

ArrayList底层源码分析之list.add方法

list.add方法源码分析 前言:本人第一次写文章,如果文章中有地方表达的不够正确或不清楚请指出来,我会加以改正。还请多多包含。 正文:相信在日常撸代码的过程中大家用到ArrayList集合中的场景不算少数,今天我也是突发奇想,想看下ArrayList是怎么实现的。这篇文章主要讲它的add()方法,在这之前先说明一下ArrayList中add()方法内使用到的属性,方便大家对add()方法的理解...

Mr_Cat_的博客 1221

源码分析——ArrayList的add,get,retainAll方法原理分析

ArrayList的add方法 /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first el...

随手记 1140

ArrayList构造函数和add方法源码分析

ArrayList构造器 /** * 初始容量大小 */ private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private static final Object[] DEFAULTCAPACITY_EMPTY_E...

yjh1271845364的博客 501

ArrayList源码分析(源码只备注add方法过程)

package com.lidl.com.lidl.web; import java.util.*; public class ArrayListTest { public static void main(String[] args) { List<String> list = new ArrayList<>(); list...

李度的博客 335

ArrayList的add()方法扩容原理,源码分析

ArrayList的add()方法扩容原理,源码分析

java架构师分享,有问题可以联系我 178

ArrayList的add()方法源码分析(jdk1.8)

成员变量 //默认的初试容量 private static final int DEFAULT_CAPACITY = 10; // 当你造了一个指定长度为0的数组,就会把elementData实例化为这个长度为0的数组 private static final Object[] EMPTY_ELEMENTDATA = {};、 // 当你造一个默认长度ArrayList时,就会把emementData实例化为这个长度为0的数组 private static final Object[] DEFAULT.

qq_50748627的博客 696

java集合 arrayList源码分析add方法自动扩容机制(上)

一、ArrayList简介 1.1、ArrayList概述 1)ArrayList是可以动态增长和缩减的索引序列,它是基于数组实现的List类。 2)该类封装了一个动态再分配的Object[]数组,每一个类对象都有一个capacity属性,表示它们所封装的Object[]数组的长度,当向ArrayList中添加元素时,该属性值会自动增加。  3)ArrayList的用法和Vector向类似,但是Vector是一个较老的集合,具有很多缺点,不建议使用。 4)ArrayList和Collection的关系

小码农吗 465

ArrayList底层源码分析--扩容机制、构造方法、add方法

ArrayList底层源码分析--扩容机制、构造方法、add方法

温涛的博客 218

Java容器:ArrayList源码分析(2 add方法)

在list后面插入一个元素。* 指定插入位置(下标)插入元素。

20年码农 376
上一篇: 深入理解MVC
下一篇: JSP运行原理分析
zcczero
博客等级 码龄9年 38粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值