前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >*ArrayList实现原理及源码学习(JDK 1.8.0)*

*ArrayList实现原理及源码学习(JDK 1.8.0)*

原创
作者头像
一半是我
修改2020-04-07 12:09:10
4570
修改2020-04-07 12:09:10
举报
文章被收录于专栏:Java学习INGJava学习ING

*ArrayList实现原理及源码学习(JDK 1.8.0)*

说明:ArrayList类的继承关系

附-图
附-图

(1)继承自抽象类AbstractList;

(2)实现了List接口,拥有List的基本功能;

(3)实现了RandomAccess接口,拥有随机读写的功能;

(4)实现了Cloneable,可以被克隆;

(5)实现了Serializable接口,并重写了序列化和反序列化方法,使得ArrayList拥有更好的序列化性能。

一、ArrayList的基本属性

图-1.1
图-1.1

二、ArrayList的构造方法(3种)

图-2.1
图-2.1

注:

关于第3种构造方法,首先调用给定集合(collection)的toArray()方法将其转换为一个数组并赋值给 elementData ;size 是集合的大小,当通过别的集合来构造ArrayList的时候,需要赋值 size。size不为0时,接下来的if条件语句是判断c.toArray()返回的结果是否正确,如果不正确则利用Arrays.copyOf方法将集合c中的元素复制到elementData数组中;size为0则将EMPTY_ELEMENTDATA空实例赋给elementData。

三、ArrayList的常用方法

1.添加元素方法

图-3.1.1
图-3.1.1
图-3.1.2
图-3.1.2

注:在上述add操作中,按照方法调用的顺序看下来,

(1)在 calculateCapacity(int minCapacity) 方法中,判断了是否使用的默认无参构造,如果是则返回的最小容量为Math.max(DEFAULT_CAPACITY,size+1),反之返回传入的size+1;

(2)modCount字段是用来记录修改过容量的次数,调用ensureExplicitCapacity()方法意味着确定修改容器的大小,即确认扩容;

(3)在grow(int minCapacity)方法中,先按原数组长度elementData.length的1.5倍扩容,如果1.5倍扩容不能满足最小容量,则将最小容量作为扩容后的数组容量;如果按1.5倍扩容超过MAX_ARRAY_SIZE,则对newCapacity进行合理性约束;

(4)最后,拷贝原数组中的数据到扩容后的新数组,并赋给elementData。

图-3.1.3
图-3.1.3
图-3.1.4
图-3.1.4

注:在上述的add操作中,

(1)首先检查指定的插入位置是否合法;

(2)接着进行数组扩容操作;

(3)然后是影响ArrayList插入删除效率的关键操作——数据搬移,将指定位置开始及其以后的所有元素向后移动,为所插入元素腾出空间;

(4)最后插入元素,元素个数size加1。

图-3.1.5
图-3.1.5

注:和上述两个添加元素的操作不同之处在于是批量插入元素,需要先将集合转成数组,若传入的集合为null将抛出空指针异常,其他操作类似。

2.删除元素方法

图-3.2.1
图-3.2.1
图-3.2.2
图-3.2.2

注:

第1个remove()是删除指定位置处的元素,需要进行下标合法性检查,按照索引直接取得元素值,返回删除的数据,将后面的元素向前移;

第2个remove()是删除指定元素,需要对元素是否为null分情况讨论,元素为null时不能调用元素对象的equals方法。(经验证,当列表中有多个相同数据时,只会删除遍历遇到的第1个数据,正如源码中所示,删除一次就return)

图-3.2.3
图-3.2.3

注:

上述方法为批量删除元素和批量保留元素(实质也是批量删除,即删除不在集合中的所有元素),都会先对集合 c 进行是否为null判断处理,调用Objects.requireNonNull方法,若为null抛出空指针异常。如果在操作中途出现异常,会导致 r != size,则将出现异常后面的数据全部复制覆盖到数组中,如下源码所示:

图-3.2.4
图-3.2.4

3.修改元素方法

图-3.3.1
图-3.3.1

注:

对指定索引进行合法性检查,oldValue保留旧值,然后用新值覆盖旧值,返回oldValue。

4.查询元素方法

图-3.4.1
图-3.4.1

5.遍历ArrayList中的对象(迭代器方法)

图-3.5.1
图-3.5.1

注:

在获取集合的迭代器的时候,去new了一个Itr对象,而Itr实现了Iterator接口,我们主要关注Iterator接口的常用的方法hasNext(),next(),remove()方法。

(1)cursor:下一个元素的下标

(2)lastRet:上一次返回元素的下标

(3)hasNext():判断是否还有元素

(4)next():按照cursor的递增逐个取出元素

(5)remove():删除元素,如果异步进行了删除操作将会抛出异常

6.其他方法

图-3.6.1
图-3.6.1
图-3.6.2
图-3.6.2
图-3.6.3
图-3.6.3

四、小结ArrayList特点

1.有序:指的是插入元素的顺序和取出元素的顺序一致;

2.可重复:指的是可以插入重复的元素;

3.按索引查找元素效率高,增删元素效率较低(尾插尾删例外):

原因是查找的时候根据索引可一步到位获取元素值,而增删操作涉及大量的数据搬移操作;

4.线程不安全:

首先源码中的各个操作都没有synchronized字段,以add为例,当插入元素的时候,elementData[size++] = e可以理解为两步操作,

①elementData[size] = e;②size++;我们都知道CUP是切换进程运行的,在单线程中这样是没有问题的,但是很多情况是在多线程中使用ArrayList的,这时候比如有两个线程,线程 A 先将元素存放在位置 0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此 ArrayList 添加元素,因为此时 size 仍然等于 0 ,所以线程B也将元素存放在位置0,然后线程B增加size的值,接着线程A运行,也增加 size 的值,这样最后得到的元素实际上只有一个,存放在位置 0,而 size 却等于 2,因此造成了线程不安全。

5.适用场景:高频的查询操作和尾部增删操作的情况下可以选用。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • *ArrayList实现原理及源码学习(JDK 1.8.0)*
    • 说明:ArrayList类的继承关系
      • 一、ArrayList的基本属性
        • 二、ArrayList的构造方法(3种)
          • 三、ArrayList的常用方法
            • 1.添加元素方法
            • 2.删除元素方法
            • 3.修改元素方法
            • 4.查询元素方法
            • 5.遍历ArrayList中的对象(迭代器方法)
            • 6.其他方法
          • 四、小结ArrayList特点
          相关产品与服务
          文件存储
          文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档