程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

Java集合框架(三):JDK1.8的ArrayList源码解析

发布于2021-06-08 11:12     阅读(171)     评论(0)     点赞(21)     收藏(1)


ArrayList

在这里插入图片描述

可以看到,他依然还是继承了AbstractList与实现了List接口,这个与JDK1.7的没啥区别

变量与常量

在这里插入图片描述
可以看到,这个相比于jdk1.7的多出来了一常量Object数组,名字为DEFAULTCAPACITY_EMPTY_ELEMENTDATA

构造方法

在这里插入图片描述
可以看到无参构造使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,而使用指定容量的构造方法,当容量为0时,使用的是EMPTY_ELEMENTDATA。

即将无参构造的空数组与指定容量为0的有参构造方法区分开来

  • 共同点是:数组都是空数组
  • 不同点是:数组不是同一个对象

我们来看一下为什么要加这个DefaultCapacity_empty_elementData空数组
在这里插入图片描述
注释上说,是为了了解添加第一个元素时要膨胀多少

增加元素

在这里插入图片描述
可以看到add方法与JDK1.7是几乎一样的,步骤都是

  • 检查底层Object数组容量
  • 在底层Object数组对应位置增加值
  • 返回true

扩容

接下来,我们看看ensureCapacityInternal与ensureExplicitCapacity是怎么执行的
在这里插入图片描述
这里是一个与JDK1.7的不同点,我们回顾一下JDK1.7的版本是怎样的
在这里插入图片描述
JDK1.7是要先针对第一次的无参构造产生的elementData进行扩容(要设置默认容量为10)

但JDK1.8却没有针对第一次的无参构造产生的空数组进行扩容,但其还调用了另一个方法calculateCapacity来进行计算需要的容量

那接下来就看看,这个方法做了什么

在这里插入图片描述
可以看到,这个calculateCapacity方法做的内容跟JDK1.7的ensureCapacityInternal的第一步针对无参构造的判断几乎是一致,JDK1.8只不过将这一步拆分出来放在了calculateCapacity里

然后ensureExplicitCapacity是一致的,都是ensureCapacityInternal最后都要进行调用的方法,判断当前新增所需的容量大于当前的容量,大于就要进行扩容

接下来看看grow方法
在这里插入图片描述
跟JDK1.7也是一样的,没有任何变化

  • 默认扩容规则为1.5倍
  • 如果扩容后的容量仍然不够,即仍然小于增加元素所需的容量,那么扩容后的新容量改为增加元素所需的容量
  • 判断扩容后的容量是否大于MAX_ARRAY_SIZE(值为Integer最大值减8)
    • 如果大于,就需要更大的容量,调用hugeCapacity
      在这里插入图片描述
      可以看到,最大值顶多就是Integer的最大值

接下来,我们看看另一个add方法
在这里插入图片描述
可以看到,跟JDK1.7的是一样的,连rangeCheckForAdd都是一样的
在这里插入图片描述
步骤也是一样的

  • 判断指定index是否合理
  • 判断容量是否足够
  • 使用arrayCopy将底层Object数组向后移一位,腾出index位置出来
  • 将底层Object数组的index位置赋上指定的值
  • 最后让size++

删除元素

clear方法

在这里插入图片描述
可以看到clear方法也是没变的,跟jdk1.7一摸一样

也是遍历底层Object数组,然后逐个设置为Null,让gc收集不要的引用

remove index方法

在这里插入图片描述
跟jdk1.7也是一摸一样的

  • 检查index是否合理
  • modCount自增,代表底层数组发生变化
  • 使用elementData获取旧的数据
  • 调用arrayCopy方法将底层Object数组向前移一位,空出最后一个位置
  • 让最后一个位置设置为Null,顺便让size自增,代表元素少一个
  • 设置为null,让gc回收不要的引用

remove object方法

在这里插入图片描述
也是跟JDK1.7一样,丝毫没有变过

  • 分为null和非null两种情况
  • null使用双等于号,非null使用equals判断是否相等
  • 遍历底层数组,去进行匹配符合的索引
  • 调用fastRemove去移除匹配的索引

看一下fastRemove方法
在这里插入图片描述

也是跟JDK1.7没用,没变的

调用arraycopy去将底层数组指定索引后面的那些元素往前移动一位,然后删除最后一位,将最后一位设为Null,让gc回收不要的引用

修改元素

修改元素只有一个set方法
在这里插入图片描述
步骤如下

  • 检查索引是否合理
  • 调用elementData返回旧的数据
  • 底层数组对应的index位置修改新的数据
  • 返回旧的数据

克隆

在这里插入图片描述
克隆的方法也是基本没变过的,也是浅拷贝

总结

JDK1.7与JDK1.8的ArrayList几乎是相差无几的,不过在早期的JDK1.7好像无参构造方法是直接调用this(10)去调用指定容量的构造方法

不同点总结一下

  • jdk1.8封装了jdk1.7的ensureCapacityInternal一部分代码,封装进了calculateCapacity方法里面,这部分是针对第一次调用无参构造方法底层Object数组的默认容量来设计的
  • jdk1.8将无参构造的空数组,与指定容量为0的有参构造方法的空数组区分了开来,设置了两个不同的空数组,但jdk1.7只针对了无参构造的设置了空数组

原文链接:https://blog.csdn.net/GDUT_Trim/article/details/117574669



所属网站分类: 技术文章 > 博客

作者:java小王子

链接:http://www.javaheidong.com/blog/article/219441/b073d1841f3f612b12a0/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

21 0
收藏该文
已收藏

评论内容:(最多支持255个字符)