java集合中ArrayList源码解析是怎样的
发表于:2025-01-25 作者:千家信息网编辑
千家信息网最后更新 2025年01月25日,今天就跟大家聊聊有关java集合中ArrayList源码解析是怎样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。整体架构ArrayList实
千家信息网最后更新 2025年01月25日java集合中ArrayList源码解析是怎样的
今天就跟大家聊聊有关java集合中ArrayList源码解析是怎样的,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
整体架构
ArrayList实际就是个数组结构,如图
index:数组下标
elementData:数组本身
其他基本概念:
/** * Default initial capacity. * 数组初始大小 */ private static final int DEFAULT_CAPACITY = 10;
/** * The size of the ArrayList (the number of elements it contains). * 当前数组大小 * @serial */private int size;
//表示当前数组被修改的版本次数protected transient int modCount = 0;
类注释:
1、可以自动扩容
2、允许put null
3、size、set、put、add、get时间复杂度O(1)
4、非线程安全(作为共享变量时存在),必要时可以使用线程安全的SynchronizedList(性能低)
public boolean add(E e) { synchronized (mutex) {// synchronized 是一种轻量锁,mutex 表示一个当前 SynchronizedList return c.add(e); }}
5、增强for循环或迭代时,若数组大小改变,则抛出异常
源码解析
一、初始化:
//1、指定大小初始化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); }}//2、无参初始化 数组大小为空//初始化时数组大小不是默认的10,第一次add时扩容为10public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}//3、指定初始数据初始化public ArrayList(Collection extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; }}
二、新增、扩容、删除
新增:
public boolean add(E e) { //确保数组大小是否足够,不够执行扩容,size 为当前数组的大小 ensureCapacityInternal(size + 1); // Increments modCount!! //直接赋值,线程不安全的 elementData[size++] = e; 对null无校验,因此可以存入null值 return true;}
扩容:
private void ensureCapacityInternal(int minCapacity) { //如果初始化数组大小时,有给定初始值,以给定的大小为准,不走 if 逻辑 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //确保容积足够 ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) { //记录数组被修改 modCount++; // 如果我们期望的最小容量大于目前数组的长度,那么就扩容 if (minCapacity - elementData.length > 0) grow(minCapacity);}//扩容,并把现有数据拷贝到新的数组里面去private void grow(int minCapacity) { int oldCapacity = elementData.length; // oldCapacity >> 1 是把 oldCapacity 除以 2 的意思 这里注意:ArrayList扩容是1+0.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); // 如果扩容后的值 < 我们的期望值,扩容后的值就等于我们的期望值 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 如果扩容后的值 > jvm 所能分配的数组的最大值,那么就用 Integer 的最大值 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); 扩容时源码中对上下数组大小做了校验,有很清晰的数组大小溢出意识,平时开发时应借鉴 // 通过复制进行扩容 elementData = Arrays.copyOf(elementData, newCapacity);}
扩容动态图:
删除:
public boolean remove(Object o) { // 如果要删除的值是 null,找到第一个值是 null 的删除 if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { 可以删除null值 fastRemove(index); return true; } } else { // 如果要删除的值不为 null,找到第一个和要删除的值相等的删除 for (int index = 0; index < size; index++) // 这里是根据 equals 来判断值相等的,相等后再根据索引位置进行删除 if (o.equals(elementData[index])) { //找到需要删除的索引 fastRemove(index); return true; } } return false;}//根据索引位置进行元素删除private void fastRemove(int index) { // 记录数组的结构要发生变动了 modCount++; // numMoved 表示删除 index 位置的元素后,需要从 index 后移动多少个元素到前面去 // 减 1 的原因,是因为 size 从 1 开始算起,index 从 0开始算起 int numMoved = size - index - 1; if (numMoved > 0) // 从 index +1 位置开始被拷贝,拷贝的起始位置是 index,长度是 numMoved System.arraycopy(elementData, index+1, elementData, index, numMoved); //数组最后一个位置赋值 null,帮助 GC elementData[--size] = null;}
三、迭代器
implement java.util.Iterator
迭代器的一些参数:
int cursor;// 迭代过程中,下一个元素的位置,默认从 0 开始。
int lastRet = -1; // 新增场景:表示上一次迭代过程中,索引的位置;删除场景:为 -1。
int expectedModCount = modCount;// expectedModCount 表示迭代过程中,期望的版本号;modCount 表示数组实际的版本号。
迭代器源码分析:
//是否存在下一个可迭代的值public boolean hasNext() { return cursor != size;//cursor 表示下一个元素的位置,size 表示实际大小,如果两者相等,说明已经没有元素可以迭代了,如果不等,说明还可以迭代}//下一个可迭代的值public E next() { //迭代过程中,判断版本号有无被修改,有被修改,抛 ConcurrentModificationException 异常 checkForComodification(); //本次迭代过程中,元素的索引位置 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); // 下一次迭代时,元素的位置,为下一次迭代做准备 cursor = i + 1; // 返回元素值 return (E) elementData[lastRet = i];}// 版本号比较final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException();}public void remove() { // 如果上一次操作时,数组的位置已经小于 0 了,说明数组已经被删除完了 if (lastRet < 0) throw new IllegalStateException(); //迭代过程中,判断版本号有无被修改,有被修改,抛 ConcurrentModificationException 异常 checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; // -1 表示元素已经被删除,这里也防止重复删除lastRet = -1; // 删除元素时 modCount 的值已经发生变化,在此赋值给 expectedModCount // 这样下次迭代时,两者的值是一致的了 expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); }}
看完上述内容,你们对java集合中ArrayList源码解析是怎样的有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。
数组
迭代
大小
位置
元素
版本
过程
源码
期望
安全
内容
实际
拷贝
线程
最大
场景
数据
最大值
期望值
索引
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
服务器映射到外网安全隐患
服务器记录复制操作步骤
呈贡区综合软件开发零售价格
沃思互联网科技有限公司
洛阳软银网络技术有限
我的世界网易版贝爷模组服务器
网络技术基础ppt
数据库中什么叫做自选键
拉霸机游戏用什么软件开发
企业级数据库的优缺点
上海网络技术服务保障
hdfs清空数据库
图书管理系统 数据库
数据库技术与辞书编纂
运维和数据库开发哪个是核心
数据库安全测试方案
kvm管理多个服务器
现代通信网络技术李铮课后答案
java需要数据库
软件开发哪个中心好
命令行登陆mongodb数据库
网络技术供应链
web安全测试服务器
吴中区进口网络技术质量保证
oracle数据库的scn
银川软件开发招聘信息
数据库技术及应用王成良
会计网络技术应用
华科 网络技术
万方数据库的引文网络数据