关于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的扩容机制的更多相关文章

  1. ArrayList的扩容机制

    一.ArrayList的扩容机制 1.扩容的计算方式是向右位移,即:newSize = this.size + (this.size>>1).向右位移,只有在当前值为偶数时,才是除以2:奇 ...

  2. 浅谈 ArrayList 及其扩容机制

    浅谈ArrayList ArrayList类又称动态数组,同时实现了Collection和List接口,其内部数据结构由数组实现,因此可对容器内元素实现快速随机访问.但因为ArrayList中插入或删 ...

  3. 【数组】- ArrayList自动扩容机制

    不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力, ...

  4. Java ArrayList自动扩容机制

    动态扩容 1.add(E e)方法中 ①  ensureCapacityInternal(size+1),确保内部容量,size是添加前数组内元素的数量 ②  elementData[size++] ...

  5. ArrayList动态扩容机制

    初始化:有三种方式 1.默认的构造器,将会以默认的大小来初始化内部的数组:public ArrayList(); 2.用一个ICollection对象来构造,并将该集合的元素添加到ArrayList: ...

  6. 学习ArrayList的扩容机制

    基于jdk8 1.首先我们看new ArrayList中 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDA ...

  7. 小白也能看懂的ArrayList的扩容机制

    来,话不多说进入正题!我们下面用最简单的代码创建ArrayList并添加11个元素,并 一 一 讲解底层源码:在说之前,给大家先普及一些小知识: >ArrayList底层是用数组来实现的 > ...

  8. 送分题,ArrayList 的扩容机制了解吗?

    1. ArrayList 了解过吗?它是啥?有啥用? 众所周知,Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List.Set 和 Queu ...

  9. ArrayList源码解析(二)自动扩容机制与add操作

    本篇主要分析ArrayList的自动扩容机制,add和remove的相关方法. 作为一个list,add和remove操作自然是必须的. 前面说过,ArrayList底层是使用Object数组实现的. ...

随机推荐

  1. Xml格式的Bared和Warpped

    Bared   Wrapped  

  2. This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.

    Attempt to load Oracle client libraries threw BadImageFormatException. This problem will occur when ...

  3. linux系统中ls命令的用法

    普通文件: -,f目录文件: d链接文件(符号链接): L设备文件:字符设备:c块设备:b命名管道: p套接字文件: s linux文件时间戳 时间分为三种类型:创建时间,修改时间:open访问时间: ...

  4. 微服务架构之「 下一代微服务 Service Mesh 」

    Service Mesh 被大家称为下一代的微服务,是微服务领域的一颗新星,被大家讨论的非常多. 我在大家的讨论中,还看到有人说 “目前的微服务架构我都没学会呢,现在又来一个下一代微服务,真学不动了” ...

  5. vs2015 生成 cordova 页面中文乱码

    原文:vs2015 生成 cordova 页面中文乱码 1.用VS2015新创建Cordova项目,启动运行index.html 中文显示乱码 解决方案: 1.使用text/html通用解析编码utf ...

  6. 快速写入Xml文件

    我们在做一些操作的时候会需要生成日志,Xml文件就是我们常用的一种日志文件. 普通操作Xml文件的代码遇到大数据量的话就很慢了. 用这个生成Xml文件的话,即使数据量很大,也很快 private vo ...

  7. 【转】微信退款时候报”请求被中止: 未能创建 SSL/TLS 安全通道“或”The request was aborted: Could not create SSL/TLS secure channel“的错误

    退款测试在我本机测试一切都是正常的,但是发布到了服务器就报这样的一个错啦 但是无论百度或者google或者bing,你能够搜索到的结果都很类似,综合起来就是加这样一些代码,如下 ServicePoin ...

  8. Android adb socket 连接失败的问题

    pc客户端通过adb forward tcp 与android app通信 场景:pc启动,能正常建立连接,当断开连接再次连接,偶现pc客户端无法与forward 的端口建立 socket连接,连接请 ...

  9. 零元学Expression Blend 4 - Chapter 25 以Text相关功能就能简单做出具有设计感的登入画面

    原文:零元学Expression Blend 4 - Chapter 25 以Text相关功能就能简单做出具有设计感的登入画面 本章将交大家如何运用Blend 4 内的Text相关功能做出有设计感的登 ...

  10. 有什么很好的软件是用 Qt 编写的?(尘中远)

    作者:尘中远链接:http://www.zhihu.com/question/19630324/answer/19365369来源:知乎 http://www.cnblogs.com/grandyan ...