一.首先来看一下ArrayList的类图:

1,实现了RandomAccess接口,可以达到随机访问的效果。

2,实现了Serializable接口,可以用来序列化或者反序列化。

3,实现了List接口,是List的实现类之一

4,实现了Collection接口,是Collection家族的成员之一

5,实现了Iterable接口,代表可以对ArrayList进行For-each遍历。

二.然后咱们来看一下ArrayList的相关属性:

1,Long serialVersionUID = 8683452581122892189L,ArrayList序列化的版本ID。

2,Int DEFAULT_CAPACITY = 10,默认的初始容量为10

3,Final Object[] EMPTY_ELEMENTDATA = {},用于空实例的共享空数组实例。(new ArrayList(0))

4,Final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {},用于提供默认大小的实例的共享空数组实例。(new ArrayList())

5,transient Object[] elementData。存储ArrayList的数组缓冲区,ArrayList的容量是数组的长度。

6,Int size,ArrayList中元素的数量。

三.接着来看一下ArrayList的构造方法:

有参构造方法:很清晰的可以看出,如果initalCapacity>0,那么就创建一个新的长度为initalCapacity的ArrayList,如果initakCapacity=0,就用空实例的共享空数组实例EMPTY_ELEMENTDATA。其他情况就抛出非法请求。

无参构造方法:也可以很清晰的看出,如果用户不传入初始容量,那么ArrayList就会使将默认大小的实例的共享空数组实例赋值给elementData。

带集合参数的构造方法:

这也是将集合转换为数组的一个方法。@param c,集合,代表集合中的元素都会被放到List当中。@throws 如果集合为空,就抛出空指针异常。为了防止c.toArray不正确的执行,导致没有返回一个Object[],进行了相关的特殊处理。如果数组的大小等于0的话,那么就将默认的数组空实例大小赋值给elementData。

四.测试异常

那么为什么c.toArray会不返回一个Object[].class呢?来咱们写一些测试类,来测试一下。 

如果c.toArray一直会返回Object[].class,那么输出的结果都会是java.lang.Object。但是测试结果如下图。显然从测试结果上,可以看出java.util.ArrayList会返回一个Object对象,但是java.util.Arrays$ArrayList(Array的私有内部类ArrayList)却返回了String对象。这是为什么呢?

翻看ArrayList的toArray方法,会发现使用了Array.copyOf方法。

那么我们继续往下走,看一下这个copyOf方法已经该方法的具体实现形式。

通过这个三元运算符,也能够看出这一个复制的逻辑。如果newType是Object类型的话,那么就返回数组的类型为Object,如果不是的话,就是newType类型的。而我们在ArrayList的toArray方法里面放入的elementData前面已经讲解过是Object类型的,所以ArrayList必然就是一个Object类型。

看完ArrayList内部的toArray源码之后,我们来看一下Array中的内部ArrayList的源码:

只截取了部分源码,可以看出内置的ArrayList是直接把接收到的数组赋值给a,然后通过toArray方法,直接把a的克隆返回,而这是传入的数据是什么类型,返回的就是什么类型。所以,在我们上面的例子中,实际上返回的是String类型的数组,再将其中的元素赋值成Object类型的,自然报错。

好,看完了ArrayList的属性和构造方法,咱们来看一下ArrayList的相关方法。

五.添加元素

在列表的最后添加元素,同时在父类中的abstractList中有记录modCount属性,用来记录数组修改的次数。

在指定位置添加指定的元素:

Index代表插入元素的位置,如果当前位置已经有了元素的话,那么就将该元素和元素后面的所有元素向后移一位,可能会抛出IndexOutOfBoundsException。这时候就需要考虑扩容了。

而这两个插入的方法还需要调用一些相关的私有方法。去计算当然的容量,保证ArrayList的容量健康,源码放下面了,因为比较简单,就不多说啦。

六.扩容机制

添加方法自然和扩容是分不开的。ArrayList自然也是有一套非常完善的扩容机制的,先前不是说了吗,如果在添加元素的时候容量不足,自然就需要扩容了。

1,MAX_ARRAY_SIZE代表了整个数组最大可以分配到的size,一些虚拟机再数组中预留了一些header—words,如果想要尝试分配更大的size,很有可能会报OOM的错误。

2,minCapacity:期望的最小容量,所以扩容一定要比这个数大。

3,最大容量返回Inter.MAX_VALUE。

正常情况下,新容量是原来容量的1.5倍,如果原容量的1.5倍比minCapacity小,那么就扩容到minCapacity,特殊情况扩容到Inter.MAX_VALUE

这也就解释了为什么为什么空实例默认数组有的时候是EMPTY_ELEMENTDATA,而又有的时候是DEFAULTCAPACITY_EMPTY_ELEMENTDATA。New ArrayList()会将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,new ArrayLIst(0),会将elementData赋值为EMPTY_ELEMENTDATA。后者添加元素会扩容到容量为1,前者扩容之后容量为10。

七.删除的方法

删除指定下面元素的方法

1,index:删除的指定下标

2,下标越界会抛出IndexOutOfBoundsException

删除指定元素的方法

如果存在,那么删除返回true,否则的话返回false,o表示指定的元素

私有的移除方法:

私有的删除方法,跳过边界检查且不返回移除的元素。

八.查找的方法

查找指定元素所在的位置

查找指定位置的元素

这个方法直接返回elementData数组指定下标的元素,效率还是很高的,所以ArrayList的for循环遍历的效率还是很高的。

九.序列化方法

ArrayList是可以序列化和反序列化的,具体实现的方法如下:

将ArrayList的实例的状态保存到一个流里面。

根据一个流重新生成一个ArrayList。根据序列化的方法可以看出,elementData之所以用transient修饰,是因为JDK不想将整个elementData都序列化或者反序列化,而只是将size和实际存储的元素进行序列化或者反序列化,从而节省空间和时间。

十.创建子数组

SubList的set()方法,是直接修改ArrayList中的elementData数组的,所以在使用的时候一定要注意,同时SubList是没有实现Serializable接口的,所以是不能序列化的。

十一.迭代器

创建迭代器的方法,和Itr相关属性,hasNext()方法和next方法,cursor表示下一个要返回的元素的下标,lastRet表示最后一个元素的下标,没有元素返回-1,expectedModCount表示期望的count。

在迭代的时候,会检验modCount是否等于expectedModCount,不等于的话就会抛出著名的ConcurrentModificationException异常。

数据结构——ArrayList的源码分析(你所有的疑问,都会被解答)的更多相关文章

  1. ArrayList迭代器源码分析

    集合的遍历 Java集合框架中容器有很多种类,如下图中: 对于有索引的List集合可以通过for循环遍历集合: List<String> list = new ArrayList<& ...

  2. ArrayList的源码分析

    在项目中经常会用到list集合来存储数据,而其中ArrayList是用的最多的的一个集合,这篇博文主要简单介绍ArrayList的源码分析,基于JDK1.7: 这里主要介绍 集合 的属性,构造器,和方 ...

  3. ArrayList实现源码分析

    本文将以以下几个问题来探讨ArrayList的源码实现 1.ArrayList的大小是如何自动增加的 2.什么情况下你会使用ArrayList?什么时候你会选择LinkedList? 3.如何复制某个 ...

  4. ArrayList方法源码分析

    本文将从ArrayList类的存储结构.初始化.增删数据.扩容处理以及元素迭代等几个方面,分析该类常用方法的源码. 数据存储设计 该类用一个Object类型的数组存储容器的元素.对于容量为空的情况,提 ...

  5. 集合之ArrayList的源码分析

    转载请注明出处 一.介绍 对于ArrayList,可以说诸位绝不陌生,可以说是在诸多集合中运用的最多一个类之一,那么它是怎样构成,怎样实现的呢,相信很多人都知道数组构成的,没毛病,如果遇到面试的时候, ...

  6. Java——ArrayList底层源码分析

    1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...

  7. 迎难而上ArrayList,源码分析走一波

    先看再点赞,给自己一点思考的时间,思考过后请毫不犹豫微信搜索[沉默王二],关注这个长发飘飘却靠才华苟且的程序员.本文 GitHub github.com/itwanger 已收录,里面还有技术大佬整理 ...

  8. ArrayList<E>源码分析

    ArrayList是按照线性表结构实现的 ArrayList的主要继承结构 public class ArrayList<E> extends AbstractList<E> ...

  9. ArrayList构造方法源码分析

    首先看一下无参的构造方法: private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Object ...

随机推荐

  1. POJ 跳蚤

    Z城市居住着很多只跳蚤.在Z城市周六生活频道有一个娱乐节目.一只跳蚤将被请上一个高空钢丝的正中央.钢丝很长,可以看作是无限长.节目主持人会给该跳蚤发一张卡片.卡片上写有N+1个自然数.其中最后一个是M ...

  2. 详解 TreeMap

    (有关Map集合的基本性质,请观看本人博文-- <详解 Map集合>) TreeMap: 特点: TreeMap 键不允许插入null 键的底层数据结构是红黑树,可保证键的排序和唯一性 线 ...

  3. API联调神器PostMan使用详解

    简介 创建 + 测试:创建和发送任何的HTTP请求,请求可以保存到历史中再次执行 Organize:使用Postman Collections为更有效的测试及集成工作流管理和组织APIs docume ...

  4. linux 文件的查找和压缩

    1.使用 locate 命令 需要安装:yum install mlocate -y 创建或更新 slocate/locate 命令所必需的数据库文件:updatedb 作用:搜索不经常改变的文件如配 ...

  5. Springboot:员工管理之修改员工(十(8))

    构建员工修改请求 com\springboot\controller\EmployeeController.java /*调转到员工修改页 携带员工信息 restful风格*/ @GetMapping ...

  6. 云开发静态网站托管现已支持 Angular 应用

    云开发静态托管是云开发提供的静态网站托管的能力,静态资源(HTML.CSS.JavaScript.字体等)的分发由腾讯云对象存储 COS 和拥有多个边缘网点的腾讯云 CDN 提供支持. 在云开发静态托 ...

  7. Caused by: java.io.IOException: Type mismath in vlaue from map: excepted org.apache.hadoop.io.InaWritable,received SC

    解决办法: 看map和reduce的输入是不是对应,看看map和reduce设置的参数和下面的是否一致

  8. 只会Vue怎么开发小程序?vue和微信小程序的到底有哪些区别?

    写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别. 一.生命周期 先贴两张生命周期图对比下: vue生命周期 小程序生命周期 相比之下,小程序的钩子函数要简单得多. v ...

  9. 免费申请通配符类型SSL证书

    折腾起因 最近做了个小网站wawoo.fun,一个做mac壁纸的小网站,网站还处在初级阶段,不能跟大神的比.网站发布后发现因为没有使用https,谷歌浏览器会在地址栏提示网站不安全.因此想提升下网站的 ...

  10. uniqid用法

    uniqid():妙用就是以当前时间微妙为单位,返回的唯一ID 我们可以用到密码加密和接口加密的功能上,比如 $salt = substr(uniqid(rand()), -6);//截取倒数6位$p ...