综合百科

Java中ArrayList底层扩容原理以及扩容操作的示例分析

arraylist是Java集合框架中比较常用的一个数据结构,它的底层是是基于数组实现的。

第一章 前言概述

第01节 概述

底层说明

ArrayList是List的实现类,它的底层是用Object数组存储,线程不安全

后期应用

适合用于频繁的查询工作,因为底层是数组,可以快速通过数组下标进行查找

第02节 区别

body>
区别方向ArrayList集合LinkedList集合
线程安全不安全不安全
底层原理Object类型数组双向链表
随机访问支持(实现 RandomAccess接口)不支持
内存占用ArrayList 浪费空间, 底层是数组,末尾预留一部分容量空间LinkedList占用空间比ArrayList多,存在头尾地址值占用空间

小结

ArrayList 集合的特点:

1. 线程不安全

2. 底层数据结构是数组(查询快,增删慢,支持快速随机访问)

3. 内存占用会存在部分浪费,末尾会预留一部分容量空间

第二章 核心代码

第01节 成员变量

代码

publicclassArrayList<E>extendsAbstractList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{/***默认初始容量大小,默认初始化容量为10*/privatestaticfinalintDEFAULT_CAPACITY=10;/***空数组。当集合内容置空的时候,底层使用空数组标记*/privatestaticfinalObject[]EMPTY_ELEMENTDATA={};/***用于无参数构造方法,创建对象的时候,使用这个数组定义。*相比上面的数组EMPTY_ELEMENTDATA可以进行区分,知道在添加元素的过程当中,容量增加多少*/privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};/***保存ArrayList数据的数组,这个数组会不断的改变,前面没有被final修饰表示地址值会发生的变化*/transientObject[]elementData;//non-privatetosimplifynestedclassaccess/***ArrayList所包含的元素个数,也就是在ArrayList集合底层,通过size()方法,获取到的元素个数*/privateintsize;}

补充

1.ArrayList集合底层存在6个成员变量还有一个privatestaticfinallongserialVersionUID=8683452581122892189L;序列化使用,目前针对于当前的操作过程当中,暂时不会使用得到。2.ArrayList集合当中核心的两个成员变量A.底层维护数组transientObject[]elementData;B.存储的元素个数privateintsize;

第02节 构造方法

代码

publicclassArrayList<E>extendsAbstractList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{/***构造一个初始长度为0的空数组。*/publicArrayList(){this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/***在构造方法当中,传递一个参数集合c,将集合c转换成为新的列表*elementData当中的数据,就是新集合存放的数据*c.toArray就是将原始集合的数据取出*如果取出的集合长度不为零的情况下,则复制参数集合c到elementData当中*如果取出的集合长度为零的情况下,则赋值为空数组EMPTY_ELEMENTDATA*/publicArrayList(Collection<?extendsE>c){elementData=c.toArray();if((size=elementData.length)!=0){if(elementData.getClass()!=Object[].class)elementData=Arrays.copyOf(elementData,size,Object[].class);}else{this.elementData=EMPTY_ELEMENTDATA;}}/***指定参数的长度大小*如果初始化的长度大于0,则返回新的数组*如果初始化的长度等于0,则返回默认的空数组作为集合this.elementData=EMPTY_ELEMENTDATA;*如果初始化的长度小于0,则出现非法参数异常*/publicArrayList(intinitialCapacity){if(initialCapacity>0){this.elementData=newObject[initialCapacity];}elseif(initialCapacity==0){this.elementData=EMPTY_ELEMENTDATA;}else{thrownewIllegalArgumentException("IllegalCapacity:"+initialCapacity);}}}

补充(一) 无参构造创建对象

补充(二)带参构造创建对象,带有int类型参数

补充(三)带参构造创建对象,带有 集合类型参数

第三章 扩容操作

第01节 扩容代码

核心方法介绍

来自于ArrayList集合当中的方法:1.publicbooleanadd(Ee){...}2.privatevoidadd(Ee,Object[]elementData,ints){....}3.privateObject[]grow()4.privateObject[]grow(intminCapacity)来自于其他类当中的功能1.Arrays.copyOf(elementData,newCapacity);表示来自于数组工具类Arrays当中的copyOf()底层使用的是System.arraycopy()方法2.Math.max(DEFAULT_CAPACITY,minCapacity)表示来自于数学工具类Math当中的max()方法,比较两个数据最大值,取较大者,返回

核心代码解释

publicclassArrayList<E>extendsAbstractList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{/***将指定的元素添加到此集合的末尾位置**modCount是来自于父类的AbstractList当中的成员变量*add(e,elementData,size)调用自己下面的重载方法*returntrue表示当前的方法,一定可以添加成功,因为List系列的集合添加数据都是允许成功的true如果是Set此方法返回false*/publicbooleanadd(Ee){modCount++;add(e,elementData,size);returntrue;}/***这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的add()方法重载调用的*参数1:表示需要添加的元素数据Ee*参数2:表示成员变量当中,需要维护管理的底层数组Object[]elementData*参数3:表示成员变量当中,size容器elementData当中存放的真实有效的数据个数*方法里面的逻辑:当size已经等于了内部容器elementData的最大长度,则准备进行扩容的操作,扩容使用grow()方法*无论上面是否进行了扩容的操作,这里都需要将添加的元素赋值到数组当中,也就是elementData[s]=e;*并且将当前成员变量的size在原始数据的基础上面,增加1,表示添加了新的元素之后,长度变化了,增加了1*/privatevoidadd(Ee,Object[]elementData,ints){if(s==elementData.length)elementData=grow();elementData[s]=e;size=s+1;}/***这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的add()方法调用的*方法的内部调用了ArrayList当中自己重载的方法grow(size+1)同时传入了参数。*这里参数的含义,表示的是集合当中总长度size+1表示在原始size基础上增加1*方法的返回值是一个新的数组,也就是扩容之后的数组*/privateObject[]grow(){returngrow(size+1);}/***这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的grow()方法调用的*这里的参数minCapacity,就是上面传入的参数size+1,也就是说最小容量minCapacity=size+1*方法体当中的执行逻辑:*1.获取到了底层维护数组的长度intoldCapacity=elementData.length;这里就是旧容量oldCapacity*2.判断旧容量oldCapacity是否小于0,也就是else的逻辑,*如果满足if当中的逻辑,则表示旧数组当中存在数据,并且旧数组并不是默认容量的空数组地址值*说明:扩容过的就不会是之前默认DEFAULTCAPACITY_EMPTY_ELEMENTDATA的地址值*在这种情况下,就会得到1.5被的数组长度整数,传递给Arrays.copyOf()方法进行扩容,得到新数组返回*如果满足else当中的逻辑,则返回DEFAULT_CAPACITY和minCapacity较大值。*说明:DEFAULT_CAPACITY值表示的是成员变量,默认为10*说明:minCapacity在低于10的时候,表示的会是扩容添加的长度1,2,3..9.10.11..*/privateObject[]grow(intminCapacity){intoldCapacity=elementData.length;if(oldCapacity>0||elementData!=DEFAULTCAPACITY_EMPTY_ELEMENTDATA){intnewCapacity=ArraysSupport.newLength(oldCapacity,minCapacity-oldCapacity,/*minimumgrowth*/oldCapacity>>1/*preferredgrowth*/);returnelementData=Arrays.copyOf(elementData,newCapacity);}else{returnelementData=newObject[Math.max(DEFAULT_CAPACITY,minCapacity)];}}}