服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 在java中ArrayList集合底层的扩容原理

在java中ArrayList集合底层的扩容原理

2021-09-06 11:00浪客川 Java教程

这篇文章主要介绍了在java中ArrayList集合底层的扩容原理,文中有非常详细的代码示例,对正在学习java的小伙伴们有一定的帮助,需要的朋友可以参考下

第一章 前言概述

第01节 概述

底层说明

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

后期应用

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

第02节 区别

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

小结

ArrayList 集合的特点:

1. 线程不安全

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

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

第二章 核心代码

第01节 成员变量

代码

  1. public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
  2.  
  3. /**
  4. * 默认初始容量大小, 默认初始化容量为10
  5. */
  6. private static final int DEFAULT_CAPACITY = 10;
  7.  
  8. /**
  9. * 空数组。当集合内容置空的时候,底层使用空数组标记
  10. */
  11. private static final Object[] EMPTY_ELEMENTDATA = {};
  12.  
  13. /**
  14. * 用于无参数构造方法,创建对象的时候,使用这个数组定义。
  15. * 相比上面的数组 EMPTY_ELEMENTDATA 可以进行区分,知道在添加元素的过程当中,容量增加多少
  16. */
  17. private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  18.  
  19. /**
  20. * 保存ArrayList数据的数组,这个数组会不断的改变,前面没有被 final 修饰表示地址值会发生的变化
  21. */
  22. transient Object[] elementData; // non-private to simplify nested class access
  23.  
  24. /**
  25. * ArrayList 所包含的元素个数,也就是在 ArrayList 集合底层,通过 size()方法,获取到的元素个数
  26. */
  27. private int size;
  28. }

补充

  1. 1. ArrayList 集合底层存在6个成员变量
  2. 还有一个 private static final long serialVersionUID = 8683452581122892189L;
  3. 序列化使用, 目前针对于当前的操作过程当中, 暂时不会使用得到。
  4.  
  5. 2. ArrayList 集合当中核心的两个成员变量
  6. A. 底层维护数组 transient Object[] elementData;
  7. B. 存储的元素个数 private int size;

第02节 构造方法

代码

  1. public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
  2.  
  3. /**
  4. * 构造一个初始长度为0的空数组。
  5. */
  6. public ArrayList() {
  7. this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  8. }
  9.  
  10. /**
  11. * 在构造方法当中,传递一个参数集合c,将集合 c 转换成为新的列表
  12. * elementData 当中的数据,就是新集合存放的数据
  13. * c.toArray 就是将原始集合的数据取出
  14. * 如果取出的集合长度不为零的情况下,则复制 参数集合c 到 elementData 当中
  15. * 如果取出的集合长度为零的情况下,则赋值为空数组 EMPTY_ELEMENTDATA
  16. */
  17. public ArrayList(Collection<? extends E> c) {
  18. elementData = c.toArray();
  19. if ((size = elementData.length) != 0) {
  20. if (elementData.getClass() != Object[].class)
  21. elementData = Arrays.copyOf(elementData, size, Object[].class);
  22. } else {
  23. this.elementData = EMPTY_ELEMENTDATA;
  24. }
  25. }
  26.  
  27. /**
  28. * 指定参数的长度大小
  29. * 如果初始化的长度大于0,则返回新的数组
  30. * 如果初始化的长度等于0,则返回默认的空数组作为集合 this.elementData = EMPTY_ELEMENTDATA;
  31. * 如果初始化的长度小于0,则出现非法参数异常
  32. */
  33. public ArrayList(int initialCapacity) {
  34. if (initialCapacity > 0) {
  35. this.elementData = new Object[initialCapacity];
  36. } else if (initialCapacity == 0) {
  37. this.elementData = EMPTY_ELEMENTDATA;
  38. } else {
  39. throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
  40. }
  41. }
  42. }

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

在java中ArrayList集合底层的扩容原理

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

在java中ArrayList集合底层的扩容原理

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

在java中ArrayList集合底层的扩容原理

第三章 扩容操作

第01节 扩容代码

核心方法介绍

  1. 来自于 ArrayList 集合当中的方法:
  2. 1. public boolean add(E e){ ... }
  3. 2. private void add(E e, Object[] elementData, int s){ .... }
  4. 3. private Object[] grow()
  5. 4. private Object[] grow(int minCapacity)
  6.  
  7. 来自于其他类当中的功能
  8. 1. Arrays.copyOf(elementData, newCapacity); 表示来自于 数组工具类 Arrays 当中的 copyOf() 底层使用的是 System.arraycopy() 方法
  9. 2. Math.max(DEFAULT_CAPACITY, minCapacity) 表示来自于 数学工具类 Math 当中的 max() 方法,比较两个数据最大值,取较大者,返回

核心代码解释

  1. public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
  2.  
  3. /**
  4. * 将指定的元素添加到此集合的末尾位置
  5. *
  6. * modCount 是来自于父类的 AbstractList 当中的成员变量
  7. * add(e, elementData, size) 调用自己下面的重载方法
  8. * return true 表示当前的方法,一定可以添加成功,因为List系列的集合添加数据都是允许成功的 true 如果是Set此方法返回false
  9. */
  10. public boolean add(E e) {
  11. modCount++;
  12. add(e, elementData, size);
  13. return true;
  14. }
  15.  
  16. /**
  17. * 这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的 add() 方法重载调用的
  18. * 参数1: 表示需要添加的元素数据 E e
  19. * 参数2: 表示成员变量当中, 需要维护管理的底层数组 Object[] elementData
  20. * 参数3: 表示成员变量当中, size 容器 elementData 当中存放的真实有效的数据个数
  21. * 方法里面的逻辑: 当size已经等于了内部容器 elementData 的最大长度,则准备进行扩容的操作,扩容使用 grow() 方法
  22. * 无论上面是否进行了扩容的操作,这里都需要将添加的元素赋值到数组当中,也就是 elementData[s] = e;
  23. * 并且将当前成员变量的 size 在原始数据的基础上面,增加1,表示添加了新的元素之后,长度变化了,增加了1
  24. */
  25. private void add(E e, Object[] elementData, int s) {
  26. if (s == elementData.length)
  27. elementData = grow();
  28. elementData[s] = e;
  29. size = s + 1;
  30. }
  31.  
  32. /**
  33. * 这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的 add() 方法调用的
  34. * 方法的内部调用了 ArrayList 当中自己重载的方法 grow(size + 1) 同时传入了参数。
  35. * 这里参数的含义,表示的是 集合当中总长度 size + 1 表示在原始size基础上增加1
  36. * 方法的返回值是一个新的数组,也就是扩容之后的数组
  37. */
  38. private Object[] grow() {
  39. return grow(size + 1);
  40. }
  41.  
  42. /**
  43. * 这个方法是私有方法,仅仅自己可以使用。不允许外界访问得到。便于上面的 grow() 方法调用的
  44. * 这里的参数 minCapacity ,就是上面传入的参数 size + 1,也就是说最小容量 minCapacity = size + 1
  45. * 方法体当中的执行逻辑:
  46. * 1. 获取到了底层维护数组的长度 int oldCapacity = elementData.length; 这里就是旧容量 oldCapacity
  47. * 2. 判断旧容量 oldCapacity 是否小于0,也就是 else 的逻辑,
  48. * 如果满足 if 当中的逻辑, 则表示 旧数组当中存在数据,并且 旧数组并不是 默认容量的空数组地址值
  49. * 说明: 扩容过的就不会是之前默认 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的地址值
  50. * 在这种情况下,就会得到 1.5被的数组长度整数,传递给 Arrays.copyOf()方法进行扩容,得到新数组返回
  51. * 如果满足 else 当中的逻辑,则返回 DEFAULT_CAPACITY 和 minCapacity 较大值。
  52. * 说明: DEFAULT_CAPACITY 值表示的是成员变量,默认为 10
  53. * 说明: minCapacity 在低于10的时候,表示的会是扩容添加的长度1,2,3..9.10.11..
  54. */
  55. private Object[] grow(int minCapacity) {
  56. int oldCapacity = elementData.length;
  57. if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  58. int newCapacity = ArraysSupport.newLength(oldCapacity,
  59. minCapacity - oldCapacity, /* minimum growth */
  60. oldCapacity >> 1 /* preferred growth */);
  61. return elementData = Arrays.copyOf(elementData, newCapacity);
  62. } else {
  63. return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
  64. }
  65. }
  66. }

到此这篇关于在java中ArrayList集合底层的扩容原理的文章就介绍到这了,更多相关ArrayList集合扩容原理内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/ShiShiLunHui/article/details/115671898

延伸 · 阅读

精彩推荐
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7472021-02-04
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08