在Java中,ArrayList是最常用的集合之一。它是一种容器,它的内部定义了一个Object类型的数组elementData,因此可用于存储任意类型的数据。我们知道,数组是长度恒定的。而ArrayList相当于是一个长度可变的动态数组,一起来看看的它的扩容机制
扩容机制
ArrayList是一个底层基于数组实现的集合容器。当我们在创建ArrayList对象时,默认数组长度为10,当然也可以在创建时指定长度。之后在程序执行过程中,不断地向ArrayList中添加数据。当数据存储达到底层数组最大容量时则会触发扩容机制
扩容原理
首先创建一个新的数组,新数组的长度时原数组的1.5倍。然后调用Arrays.copyOf()方法将原数组的所有数据copy到新数组中,再将当前新添加的数据添加至新数组并返回
源码分析
先来看ArrayList类生命的几个参数
当我们创建ArrayList对象并且指定长度时调用的构造器
不指定长度时构造器
需要注意的是,我们不论用上述哪个构造器,首先第一步创建出来的都是空数组,但是会在第一次添加数据的时候执行不同方法进行扩容
下面我们从调用add()方法开始分析:
每次添加数据都会将size+1去进行判断,保证数组拥有至少存储这个新数据的空间
CalculateCapacity()方法用于判断当前数组是否是默认容量的数组,如果是默认容量的数组那么此时就要确定是否是第一次添加数据
如果是第一次添加数据,那么就将返回DEFAULT_CAPACITY=10也就是minCapacity=10
如果不是第一次添加数据,就将添加新数据之后的最小容量返回
其次还要注意的是,如果在创建ArrayList对象时使用的指定长度的构造器那么就会直接返回最小容量,也就是说如果你创建ArrayList指定长度为0,那么此时就会返回minCapacity=1,指定长度为0这个清空后面给到具体分析
ensureExplicitCapacity()方法用于判断是否需要扩容,经过上述方法将最小容量minCapacity传入ensureExplicitCapacity方法,如果这个所需最小容量大于当前数组容量(也就是当前数组存不下这个新数据了)则触发扩容机制grow()方法,反之不会进行扩容
在分析grow()方法之前我们先明确两个概念:
ArrayList定义了允许存储的最大容量也就是Integer允许的范围-8,如果溢出则是负数
Integer类型的范围是: -2的31次方~2的31次方减1
下面我们来看真正实现扩容的grow()方法
值得注意的是,如果当前数组是无参构造器默认生成的空数组,并且是第一次添加数据时,那么数组的长度将会直接变为10
如果当前的数组是有参构造器(指定长度)生成并且指定初始容量为0,那么在前四次调用add方法添加数据时每次扩容都是+1,只有在第五次才会执行1.5倍扩容。
因为第一次添加则是minCapacity=1,oldCapacity=0 执行int newCapacity = oldCapacity + (oldCapacity >> 1);之后newCapacity 还是0,则执行if (newCapacity - minCapacity < 0) -->newCapacity = minCapacity;也就是1,那么newCapacity 就为1,后面的三次以此类推差不多
那么至此,ArrayList就完成了扩容
到此这篇关于Java ArrayList扩容机制原理深入分析的文章就介绍到这了,更多相关Java ArrayList扩容机制内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!