深入java集合学习2-ArrayList的实现原理

Java 集合框架HashMap 的原理 ArrayList 的原理 LinkedList 的原理 fail-fast 是一种机制,当集合在迭代过程中被修改时,它会立即抛出 ConcurrentModificationException 异常。例如,在使用迭代器遍历集合时,如果集合被修改,迭代器会检测到并发修改,并立即抛出异常。fail-safe 是一种机制,它不会抛出 ConcurrentModificationException 异常。它通过创建集合的副本来进行迭代,因此对原始集合的修改不会影响迭代过程。 阅读详情

ArrayList概述

类概述

          ArrayList是List 接口的大小可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。

每个 ArrayList 实例都有一个容量(capacity)。该容量是指用来存储列表元素的数组的大小。它大于或等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长。在添加大量元素前,应用程序可以使用 ensureCapacity 操作来增加 ArrayList 实例的容量。这可以减少递增式再分配的数量。注意,此实现不是同步的。

类结构


ArrayList实现

          通过查看ArrayList的源码我们可以得知,ArrayList底层是通过操作数组来实现,其实就是用java实现了数据结构中的顺序表。

底层采用数组实现

private transient Object[] elementData;
          看到这行代码,或许有很多同学和我刚开始一样。为什么ArrayList源代码中要将elementData定义为transient变量呢?这个问题的研究大家可以看这篇文章【 http://kakaluyi.iteye.com/blog/870137】.如果对java中的序列化知识不懂的可以看本博客中的关于序列化的文章。【 理解Java对象序列化】     【 java中可定制的序列化过程 writeObject与readObject】      【 Java中的序列化Serialable高级详解【转载】】          

可变数组

            在java中我们知道,当一个数组的长度被定义好之后,数组的长度是不可变的。那么可变数组时怎么一回事呢?其实可变数组只是 表现形式上的可变。
例如
      
int array1[]={1,2,3};//定义一个数组长度为3的整形数组,此时数组的三个元素分别为1,2,3
此时如果想添加一个元素"4"到数组中去,因为数组长度是不可变的,无法直接array[3]=4;那么此时只能借助另外一个长度为4的数组array2,将数组array1的元素拷贝到新数组array2中,再赋值array[3]=4;然后将array1的引用指向array2。此时array1的表现形式就像是可变数组了.
int  array1[]={1,2,3};
int array2[]=new int[4];
for(int i=0;i<array1.length;i++){
array2[i]=array1[i];
}
array2[3]=4;
array1=array2;
此时我们就可以想到,要想动态的实现ArrayList的可变数组,那么在ArrayList初始化的时候我们要初始化一个容量,往ArrayList中添加元素时我们要动态的改变底层数组的长度。那我们来看看jdk源码是怎么初始化和动态改变数组容量的

初始化

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

	public ArrayList() {
		this(10);
	}

	public ArrayList(Collection<? extends E> c) {
		elementData = c.toArray();
		size = elementData.length;
		if (elementData.getClass() != Object[].class)
			elementData = Arrays.copyOf(elementData, size, Object[].class);
	}

从源码中我们可以得知ArrayList提供了三种方式的构造器
            1 构造一个默认初始容量为10的空列表
           2 构造一个指定初始容量的空列表
           3 构造一个包含指定collection中元素的列表

动态调整底层数组的容量

public void ensureCapacity(int minCapacity) {
		modCount++;//Fast-Fail机制(具体机制本文章中专门有说的)
		int oldCapacity = elementData.length;
		if (minCapacity > oldCapacity) {
			Object oldData[] = elementData;
			int newCapacity = (oldCapacity * 3) / 2 + 1;
			if (newCapacity < minCapacity)
				newCapacity = minCapacity;
			elementData = Arrays.copyOf(elementData, newCapacity);
		}
	}
从源码中我们可知动态调整容量的过程是
          1 获取当前数组的大小(旧容量)
          2 如果当前要保证的容量小于旧容量,那么容量不进行扩充,反之就扩充。
          3 如果要扩充容量,那么新容量为 旧容量的1.5倍+1
             3.1  取计算出来的新容量和需要的容量中的最大值,最为最后底层数组的真实容量
             3.2  拷贝旧数组的数据到新数组中,让底层数组的引用指向新容量的数组
从上述分析可知如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。这样可以减少内存的占用和提高存储效率。


集合操作

ArrayList提供了add,set,get,delete等一系列操作。下面对ArrayList中实现这些操作一一讲解。

add添加元素

元素添加到列表的尾部

public boolean add(E e) {
		ensureCapacity(size + 1); //动态调整底层数组的容量
		elementData[size++] = e;//将元素添加到列表尾部,列表大小加1
		return true;//返回true,添加成功
	}

元素添加到指定位置



public void add(int index, E element) {
		if (index > size || index < 0)// 首先检查index是否合法,要保证不能大于列表的实际长度,且index不能为负数,如果不满足就抛出异常
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
		ensureCapacity(size + 1);// 添加元素的操作都要动态的调整底层数组的容量
		System.arraycopy(elementData, index, elementData, index + 1, size - index);//调用System的数组拷贝方法
		elementData[index] = element;// 设置新数组处index处的值为指定的元素
		size++;// 列表长度加1
	}


集合中的元素添加到列表尾部

public boolean addAll(Collection<? extends E> c) {
		Object[] a = c.toArray();
		int numNew = a.length;
		ensureCapacity(size + numNew);
		System.arraycopy(a, 0, elementData, size, numNew);
		size += numNew;
		return numNew != 0;
	}

从指定位置开始添加集合中元素


public boolean addAll(int index, Collection<? extends E> c) {
		if (index > size || index < 0)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);

		Object[] a = c.toArray();
		int numNew = a.length;
		ensureCapacity(size + numNew); // Increments modCount

		int numMoved = size - index;
		if (numMoved > 0) {
			System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
		}
		System.arraycopy(a, 0, elementData, index, numNew);
		size += numNew;
		return numNew != 0;
	}

get获取元素

我们知道ArrayList底层是通过数组实现的,那么我们就可以通过数组的索引获取元素。代码如下
public E get(int index) {
		RangeCheck(index);// 检查index是否合法

		return (E) elementData[index];// 返回指定index处的元素
	}
ArrayList中有一私有方法,来检测index是否合法。
private void RangeCheck(int index) {
		//如果index不小于列表的元素个数,就抛出异常
		if (index >= size)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
	}

remove删除元素

删除指定位置处的元素


public E remove(int index) {
		RangeCheck(index);// 检查index是否合法

		modCount++;// Fail-Fast机制
		E oldValue = (E) elementData[index];// 获取待删除的元素

		int numMoved = size - index - 1;//移动元素个数
		if (numMoved > 0) {
			System.arraycopy(elementData, index + 1, elementData, index, numMoved);//向前移动元素
		}
		elementData[--size] = null;//将原来size-1处的元素设置为空,列表大小-1
		return oldValue;//返回删除的元素
	}

删除首次出现的指定元素

ArrayList允许重复元素的存在,此方法删除的是首次出现的指定元素,要想删除指定元素内部实现过程是:(1)循环遍历列表中找到指定元素首次出现的位置 (2)删除此位置的元素,那么这样就类似remove(int index)方法。jdk内部实现代码如下:
// 删除首次出现的指定元素,元素存在返回 true,元素不存在返回false
	public boolean remove(Object o) {
		if (o == null) {
			for (int index = 0; index < size; index++)
				if (elementData[index] == null) {
					fastRemove(index);
					return true;
				}
		} else {
			for (int index = 0; index < size; index++)
				if (o.equals(elementData[index])) {
					fastRemove(index);
					return true;
				}
		}
		return false;
	}

	// ArrayList的私有方法,与remove(int index)方法类似
	private void fastRemove(int index) {
		modCount++;// Fail-Fast机制
		int numMoved = size - index - 1;
		if (numMoved > 0) {
			System.arraycopy(elementData, index + 1, elementData, index, numMoved);
		}
		elementData[--size] = null;
	}

删除指定位置区间内的元素


// 移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素
	protected void removeRange(int fromIndex, int toIndex) {
		modCount++;
		int numMoved = size - toIndex;
		System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved);
		int newSize = size - (toIndex - fromIndex);
		while (size != newSize)
			elementData[--size] = null;
	}

为什么jdk源码中此方法是protected呢?具体的解释请参考

ArrayList removeRange方法分析这篇博文。





LTspice introduction - 2 LTspice的界面 LTspice的界面主要有两个:Schematic Capture和Waveform Viewer Schematic Capture 它主要是用来画电路图的,画完电路图之后,添加一些dot 命令同时选择一些仿真的参数,点击执行(Run)Waveform Viewer 如果你的仿真不是op point的话,一个都会打开它,在它里面你可以画图相应的图形。 有两种方式可以在Viewer 阅读详情

相关推荐

ECC密码的加密和解密(附带代码实现)

ECC,全称Elliptic Curve Cryptography,是椭圆曲线密码学。这是一种公钥加密技术,其安全性基于椭圆曲线离散对数问题,被广泛应用于信息安全领域。ECC的主要优势在于,相较于RSA和DSA等其他传统的公钥密码体系,它能够在提供相同安全级别的情况下,使用更短的密钥,从而减少计算量和存储空间的需求。例如,一个256位的ECC密钥提供的安全性可以与3072位的RSA密钥或DSA密钥相媲美。ECC的主要应用领域包括SSL安全证书、安全电子邮件、移动设备安全、物联网设备安全等。

xixixi7777的博客 8271

[从零开始学习JAVA] ArrayList集合

本章节我们将介绍一个在JAVA中应用广泛的类:ArrayList集合,这个类的重量级堪比C++中的vector类,也就是说大家在以后如果要用java,就不可避免的会大量使用这个类,因此我们要认真起来,熟练的掌握这个类的应用。Arraylist是一个很实用的类,它提供了一个不会越界的数组,极大效率的提高了我们对于数据的处理效果,因此我们要熟练的掌握它,才可以制胜JAVA。

2301_80615512的博客 1394

Isaac Sim 6 利用Replicator实现高效语义分割与实例分割(实践指南5.10)

本文详细介绍了如何利用Isaac Sim 6的Replicator工具高效生成语义分割和实例分割数据集。通过虚拟环境自动标注,效率提升20倍以上,特别适用于农业机器人等计算机视觉项目。文章包含环境配置、场景构建、批量标注技巧及实例分割处理等实战指南,帮助开发者快速掌握合成数据生成技术。

weixin_42526415的博客 266

【Java集合学习1】ArrayList集合学习及集合概述分析

ArrayList集合学习及集合概述分析

weixin_43950588的博客 1738

避坑指南:QT Creator报Unknown module(s) in QT: serialport的5种解决方法

本文详细解析了Qt Creator报'Unknown module(s) in QT: serialport'错误的5种解决方法,包括检查Qt版本兼容性、安装缺失组件、配置Kit环境等。针对Windows和Linux平台提供具体操作步骤,帮助开发者快速解决串口通信模块问题,提升开发效率。

weixin_29197051的博客 157

Gerrit 使用操作手册

Gerrit是一种免费、开源的代码审查工具,使用网页交互页面。这个软件的名称来自于荷兰设计师师赫里特·里特费尔德(GerritRietveld),作者为Google公司的ShawnPearce。它使用Git作为底层版本控制系统,相比于其他的代码管理工具,Gerrit明显的特色是代码审核。利用网页浏览器,同一个团队的软件程序员,可以相互审核(Review)彼此修改后的程序代码,然后决定是继续提交还是取消提交。...

九离的博客 1万+

Ken的Java学习之路——集合ArrayList

什么是集合​ 提供一种存储空间可变的存储模型,存储的数据容量可以发生改变ArrayList集合的特点​ 长度可以变化,只能存储引用数据类型。泛型的使用​ 用于约束集合中存储元素的数据类型(类似于我们C的结构体)//下面是空参,有参,get和set方法loop:System.out.println("-----------------欢迎来到黑马学生管理系统-------------------");System.out.println("1:添加学生");

weixin_52379434的博客 824

十一种室内定位传感器方案汇总介绍与对比(机器人、物联网领域)

室内定位传感器方案汇总 目录 室内定位传感器方案汇总 1、定位方案概述 1.1、内定位系统有最基本的5种算法: 1.2、常用的室内定位技术主要包括以下几种: 1.3、定位理论 1.4、不同的定位方案对比 2、各种定位方案详细介绍 2.1、单线激光定位 2.2、多线激光定位: 2.3、视觉定位: 2.4、基于射频识别(RFID)技术室内定位 2.4.1、RFID标签(不涉及...

JK-Cool的博客 3万+

深入学习Java集合之ArrayList的实现原理

ArrayList 是List 接口的可变数组的实现,底层就是一个数组, 因此按序查找快, 乱序插入、删除因为涉及到后面元素移位所以性能慢。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。 每个ArrayList 实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向.........

小小默:进无止境 1084

10、硬件工程师笔试面试——继电器(2025版本)

在设计电路时,应综合考虑SSR的优势和局限性,确保选择合适的型号,并采取适当的设计措施来优化性能和可靠性。继电器的主要功能是利用较小的电流或电压来控制较大电流或电压的电路,实现信号的放大和隔离。在处理继电器故障时,应综合考虑电源、线圈、触点和负载等因素,及时进行故障诊断和处理,以确保电路系统的稳定性和安全性。由于汽车电子系统的复杂性,继电器的设计和选择必须考虑到系统的特定要求,包括电流容量、电压等级、环境条件(如温度、湿度、振动)以及所需的保护和隔离功能。确定线圈的工作电压或电流,以及吸合电压或电流。

XU157303764的博客 3733

贝叶斯机器学习在吸附量预测中的应用

本文介绍了贝叶斯机器学习在吸附量预测中的应用。通过Python实现完整的贝叶斯建模流程,包括数据生成、预处理、模型构建与评估。文章对比了贝叶斯与频率学派的差异,详细阐述了贝叶斯线性回归和神经网络的实现方法,并提供了数据可视化、模型诊断等技术细节。该方法不仅能预测吸附量,还能量化预测不确定性,为工程决策提供更全面的依据。全文超过6000字,结合理论推导与代码实践,是应用贝叶斯方法解决实际工程问题的完整指南。

AI的内部世界的博客 167

Java ArrayList集合的基本用法

分享一份自己整理好的Java面试手册,还有一些面试题pdf。

2401_84408780的博客 906

人体分割笔记总结

人体分割 人体分割(human parsing),属于语义分割任务的子任务,旨在对人类图像进行像素级的是细粒度分割(例如,划分出身体部位和服装)。根据不同的场景,又可以分为单人人体解析(single-person human parsing)和多人人体解析(multi-person human parsing,或者 instance-level human parsing)。除此之外,按照处理媒介分类,还可以分为基于图像的人体解析和基于视频的人体解析。 对于人体解析任务,常用的度量指标包括 Pixel a

jacke121的专栏 4255

Java学习笔记:ArrayList集合

超级详细的Java整理学习笔记:ArrayList集合、Java和python数据结构的区别,以及Java如何实现处理多样的数据组!!!

Li__Daxia的博客 1277

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Java集合之ArrayList

Java集合之ArrayList

骑着猪猪去旅行的博客 2391

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java集合框架之ArrayList

Java集合框架之ArrayListArrayList源码剖析类图RandomAccess接口成员变量构造函数无参构造器参数类型为int的构造器参数为Collection<? extends E> c的构造器成员方法trimtoSize()ensureCapacity(int minCapacity)ensureCapacityInternal(int minCapacity)ensureExplicitCapacity(int minCapacity)get(int index)set(int

weixin_43624521的博客 1013

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java集合ArrayList

众所周知,前期我们学过数组,也学习过二维的和三维的数组,更有的10维的数组都干出来过,那么我们可以使用更加强大的集合来遍历和存放数据,她可以添加和减小也可以增加和删除,可以更加方便的删除数据而不需要遍历一遍后删除在继续遍历,才可输出正常的数据而不报错!集合类和数组不一样,数组元素既可以是基本类型的值,也可以是对象(实际上保存的是对象的引用变量),而集合里只能保存对象(实际上只是保存对象的引用变量,但通常习惯上认为集合里保存的是对象)。ArrayList 类实现了可变数组的大小,存储在内的数据称为元素。

qq_39395109的博客 788

Java集合类源代码 ArrayList

Java集合arraylist源代码Arraylist的必备知识点方法详解源码 Arraylist的必备知识点 准确的来说,不是在无参来构造赋值10的,一开始new ArrayList();的时候是0,第一次调用add()方法的时候才赋值10的,ArrayList源码中就有。 方法详解 源码 package java.util; public class ArrayListextends AbstractList implements List, RandomAccess,

LEO 1482

JAVA 集合之 ArrayList

写在开头 本文作为我学习 Java 集合 ArrayList 的一个记录与总结,后续会陆续总结 JAVA 中常用的集合。 ArrayList 一、ArrayList 简介 1.1 ArrayList 概述 ArrayList 是可以动态增长或缩减的索引序列,它的底层实现是基于数组的 ArrayList 类内部维护了一个 Object[] 数组来存储元素,并维护了 Capacity 属性来表示 Object[] 数组的长度,当向 ArrayList 中添加元素时会增加 Capacity 的值 如果

an_vana的博客 323

JAVA集合源码学习——ArrayList

JAVA集合源码学习——ArrayList ArrayList概述 1)ArrayList是基于长度可动态增长的数组实现List接口的java集合类 2)ArrayList类内部维护者一个动态可再分配的Object[]数组,每一个类对象都有一个capacity属性,表示所封装的Object[]对象数组的长度,但往ArrayList添加元素时,该属性值会自动增加,体现了动态的特点 3)如果要往Arr...

优快云advancer的博客 302

Java集合详解之Arraylist的使用

今天开始,围绕集合的问题将进行一周时间的学习和练习以熟练掌握Java中集合的应用,先围绕集合概述Collection,然后对Arraylist进行学习分析介绍,并且加入大量代码练习 1.1.什么是集合 存储对象的容器,面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,存储对象,集合是存储对象最常用的一种方式。 集合的出现就是为了持有对象。集合中可以存储任意类型的对象, 而且长...

eyexin2018的博客 470

java集合学习

文章目录1.定义和框架:1.1 集合的分类:1.2collection的遍历方法: 1.定义和框架: 集合,用于更好的存储数据。原先我们使用数组进行数据存储,但是数组有一定的问题: 1.数组无法扩容,必须在定义时指定长度。 2.数组在添加,删除数据时非常麻烦。 3.数组保存的必须为同一类型的元素。 数组扩充实例: Person[] p = new Person[1]; p[0] = new Person(); //如果此时想再添加一个对象进数组,需要定义一个更大的新数组,将原数组的元素添加进去,然后进行添

hadet的博客 1190

Java学习笔记 ArrayList集合概述

1.ArrayList集合 因为数组的长度不可能发生改变,在用的时候很不方便,所以需要有一个长度可以随意变化的类,而Arraylist集合的长度是也可以随意变化的 ArrayList集合的创建,添加 import java.util.ArrayList; /* 数组的长度不可能发生改变 但是Arraylist集合的长度是也可以随意变化的 对于Arraylist来说,有一个尖括号<E>代表泛型 泛型:也就是装在集合中是所有元素,全都是统一的什么类型 注意:泛型只能是引用类型,不能是基本类型 注

qq_39286015的博客 197

JAVA集合之ArrayList

java基础有很多,但是集合肯定算是重要的一部分

qq_41820066的博客 308

【java】ArrayList集合的学习

本文中仅演示了几个较为简单的关于ArrayList集合的使用,以及使用迭代器来遍历集合,在往后的数据存储中,集合将会发挥出非常大的作用。

qq_75078220的博客 219

从一道面试题来认识java类加载时机与过程

1  开门见山 以前曾经看到过一个java的面试题,当时觉得此题很简单,可是自己把代码运行起来,可是结果并不是自己想象的那样。题目如下: class SingleTon { private static SingleTon singleTon = new SingleTon(); public static int count1; public static int count2 =

爱老婆、爱生活、爱工作、爱编程 2578
上一篇: 云计算的三种服务模式:SaaS/PaaS/IaaS
下一篇: java请求https地址如何绕过证书验证?
天魂地煞
博客等级 码龄15年 18粉丝 36原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值