关于ArrayList的扩容机制
关于ArrayList的扩容机制
ArrayList作为List接口常用的一个实现类,其底层数据接口由数组实现,可以保证O(1)
复杂度的随机查找, 在增删效率上不如LinkedList,但是在查询效率较高,相对同是数组实现的Vector,并不能保证线程安全,所以多适用于单线程环境。
由于底层是有数组实现,因为数组的长度需要初始化定义,并不能自动进行长度增加,所以ArrayList有对应的扩容机制,当增加元素时,会判断是否需要扩容,下面看源码:
首先认识ArrayList的几个重要变量:
/*序列化ID*/
private static final long serialVersionUID = 8683452581122892189L;
/*默认的数组容量,第一次进行添加操作时,如果ArrayList为空或者添加元素后的数组长度小于等于10,会将该值作为数组的初始长度*/
private static final int DEFAULT_CAPACITY = 10;
/*一个空的对象数组,在需要将elementData数组置空时,会将该对象赋予elementData*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/*默认的空对象数组,在ArrayList构造时,默认将该对象给elementData*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/*ArrayList内部用于存储元素的数组,transient关键字修饰,不使用默认序列化*/
transient Object[] elementData; // non-private to simplify nested class access
/*数组的长度,是ArrayList中实际元素的个数,不是数组的容量*/
private int size;
在ArrayList的尾部插入和其他位置虽然是不同方法,但是都使用到了ensureCapacityInternal()方法确保数组内部容量,在每次添加操作中都会使用该方法进行容量判断,之后,才会将增加的元素添加到数组中,下面以尾部插入为例;
/**
* 增加数据元素到集合得末尾
*
*/
public boolean add(E e) {
/*判断是否扩容,如果原来的元素个数是size,那么增加一个元素之后的元素个数为size + 1,所以需要的最小容量就为size + 1*/
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal()将判断委托给ensureExplicitCapacity()处理
/*获取数组最小容量*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
/*如果elementData为空,且minCapacity <= 10,都会以DEFAULT_CAPACITY作为最小容量*/
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
} private void ensureCapacityInternal(int minCapacity) {
/*ensureCapacityInternal方法委托给ensureExplicitCapacity方法*/
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
} private void ensureExplicitCapacity(int minCapacity) {
modCount++; /*如果minCapacity大于elementData的长度,使用grow方法进行扩容*/
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
下面就是扩容的实现方法grow方法:
/*扩容方法*/
private void grow(int minCapacity) {
/*原有数组容量*/
int oldCapacity = elementData.length;
/*新的数组容量,下面位运算相当于newCapacity = oldCapacity * 1.5 向下取整*/
int newCapacity = oldCapacity + (oldCapacity >> 1);
/*如果新的数组容量小于需要的最小容量,即假设新的数组容量是15,最小需要16的容量,则会将16赋予newCapacity*/
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
/*变量MAX_ARRAY_SIZE = 2147483639 [0x7ffffff7],如果扩容后的新容量大于这个值则会使用hugeCapacity方法
* 判断最小容量minCapacity是否大于MAX_ARRAY_SIZE,如果需要最小容量的也大于MAX_ARRAY_SIZE,则会以
* Integer.MAX_VALUE = 2147483647 [0x7fffffff]的值最为数组的最大容量,如果没有则会以MAX_ARRAY_SIZE最为最大容量
* MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8,为什么用MAX_ARRAY_SIZE ,源码的中的说法是一些虚拟机中会对数组保留一些标题字段
* 使用Integer.MAX_VALUE会造成内存溢出错误
* */
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
/*确定数组最终的容量newCapacity之后,将原有ArrayList的元素全部拷贝到一个新的ArrayList中*/
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
/*如果minCapacity小于0,则抛出内存溢出错误*/
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
ArrayList的扩容机制还是相对容易理解的,就是在第一个添加元素时,创建一个长度为10的数组,之后随着元素的增加,以1.5倍原数组的长度创建一个新数组,即10, 15, 22, 33,。。这样序列建立,将原来的元素拷贝到新数组之中,如果数组长度达到上限,则会以
MAX_ARRAY_SIZE 或者 Integer.MAX_VALUE作为最大长度,而多余的元素就会被舍弃掉。
关于ArrayList的扩容机制的更多相关文章
- ArrayList的扩容机制
一.ArrayList的扩容机制 1.扩容的计算方式是向右位移,即:newSize = this.size + (this.size>>1).向右位移,只有在当前值为偶数时,才是除以2:奇 ...
- 浅谈 ArrayList 及其扩容机制
浅谈ArrayList ArrayList类又称动态数组,同时实现了Collection和List接口,其内部数据结构由数组实现,因此可对容器内元素实现快速随机访问.但因为ArrayList中插入或删 ...
- 【数组】- ArrayList自动扩容机制
不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力, ...
- Java ArrayList自动扩容机制
动态扩容 1.add(E e)方法中 ① ensureCapacityInternal(size+1),确保内部容量,size是添加前数组内元素的数量 ② elementData[size++] ...
- ArrayList动态扩容机制
初始化:有三种方式 1.默认的构造器,将会以默认的大小来初始化内部的数组:public ArrayList(); 2.用一个ICollection对象来构造,并将该集合的元素添加到ArrayList: ...
- 学习ArrayList的扩容机制
基于jdk8 1.首先我们看new ArrayList中 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDA ...
- 小白也能看懂的ArrayList的扩容机制
来,话不多说进入正题!我们下面用最简单的代码创建ArrayList并添加11个元素,并 一 一 讲解底层源码:在说之前,给大家先普及一些小知识: >ArrayList底层是用数组来实现的 > ...
- 送分题,ArrayList 的扩容机制了解吗?
1. ArrayList 了解过吗?它是啥?有啥用? 众所周知,Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List.Set 和 Queu ...
- ArrayList源码解析(二)自动扩容机制与add操作
本篇主要分析ArrayList的自动扩容机制,add和remove的相关方法. 作为一个list,add和remove操作自然是必须的. 前面说过,ArrayList底层是使用Object数组实现的. ...
随机推荐
- POJ1185:火炮(减少国家)
Description 命令将军打算N*M该网络格他们的炮兵部队部署在地图上.一个N*M该地图由N行M列,每个地图格它可以是山(使用"H" 表示),也可能是平原(用"P& ...
- WPF应用程序的启动画面[Splash Screen本质分析]
原文:WPF应用程序的启动画面[Splash Screen本质分析] 不经意间发现了wpf的这个小玩意,感觉蛮有意思的.我在项目中添加了一张图片 如图: wpf-1.JPG(10.73 K) 2010 ...
- 利用WIX制作安装包(3)
原文 利用WIX制作安装包(3) 利用WIX安装服务非常简单.只需要短短几句话就可以.当我们创建好一个Windows服务之后.我们在项目中创建一个Service.wxs 文件来安装服务,并且编辑代码如 ...
- 用Delphi将数据导入到Excel并控制Excel
一.调用Excel的方法:一般情况下有两种方法调用Excel:1. 直接使用Delphi自带的组件:在Form中分别放入ExcelApplication, ExcelWorkbook和ExcelWo ...
- 应用ImageJ对荧光图片进行半定量分析
原文 应用ImageJ对荧光图片进行半定量分析 前言ImageJ是个好东西……(省略1000字)总地来说对我们的好处是:1.免费2.多功能,基本功能就很多,加上插件可以说得上是无限多(前提是你找得到, ...
- GIS基础软件及操作(十)
原文 GIS基础软件及操作(十) 练习十.网络分析 (1) 加深对网络分析基本原理.方法的认识:(2) 熟练掌握ARCGIS下进行道路网络分析的技术方法:(3) 结合实际.掌握利用网络分析方法解决地学 ...
- 零元学Expression Blend 4 - Chapter 37 看如何使用Clip修出想要的完美曲线(上)
原文:零元学Expression Blend 4 - Chapter 37 看如何使用Clip修出想要的完美曲线(上) 几何外部的 UIElement 会在呈现的配置中以视觉化方式裁剪. 几何不一定要 ...
- Redis系统管理
EXISTS/DEL exists <key>判断某个key是否存在 del <key>删除某个key *** TYPE/KEYS type <key>获取key的 ...
- Linux数据流的重定向
>覆盖内容:>>追加内容:<和>的区别在于重定向方向不一致,>表示重定向从左到右:>>和<<类似 简单的重定向 0 /dev/stdin 标 ...
- FMX App的Application的事件(各种手机的全局按键)
直接上代码,还有条经验就是SetApplicationEventHandler可注册多个事件方法. unit Unit6; interface uses System.SysUtils, Syste ...