ArrayList 底层结构和源码分析

打印 上一主题 下一主题

主题 864|帖子 864|积分 2592

ArrayList 基本介绍

ArrayList实现了List接口。它可以存储包括null的任何类型的对象,允许重复元素。ArrayList在内部使用一个数组来存储元素,当元素数量超过数组容量时,ArrayList会自动重新分配更大的内部数组,并且将现有元素复制到新数组中。ArrayList基本等同于Vector,但是ArrayList是线程不安全的(执行效率高),在多线程情况下不建议使用ArrayList。
ArrayList 源码阅读及操作机制

首先ArrayList中用来存储元素的数组是 Object 类型的数组 elementData,ArrayList的容量就是这个数组的大小。
  1. transient Object[] elementData;
复制代码
通过 debug 下面这段代码来观察ArrayList的扩容机制。
  1. public class TestArrayList() {
  2.   public static void main(String[] args) {
  3.     ArrayList list = new ArrayList();
  4.     // ArrayList list = new ArrayList(4);
  5.         for (int i = 1; i <= 10; i++) {
  6.             list.add(i);
  7.         }
  8.         for (int i = 11; i <= 15; i++) {
  9.             list.add(i);
  10.         }
  11.   }
  12. }
复制代码
grow()

该方法增加容量以确保列表至少能够容纳最小容量参数minCapacity指定的元素数量。计算得到新容量应为旧容量的 1.5 倍。如果计算得到的新容量小于需要的最小容量,则新容量应为需要的最小容量(使用无参构造器第一次添加元素时即为这种情况,第一次扩容为 10)。如果请求的数组大小超过了虚拟机的限制,可能会导致 OutOfMemoryError。最后通过数组复制copyOf.copyOf()来进行真正的扩容。
  1. public ArrayList() {
  2.   this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  3. }
复制代码
总结

当使用无参构造器创建ArrayList对象时,elementData 初始容量为 0,第一次添加元素时 elementData 扩容为 10,以后再需要扩容,按 1.5 倍来扩容。若使用有参构造器创建ArrayList对象,elementData 初始容量为指定大小,如果需要扩容,则扩容为 1.5 倍。
值得注意的是,由于每次调整容量都需要将所有元素复制到新数组中,所以在元素数量较多时,频繁地调整容量可能会导致性能下降。为了避免频繁地调整容量,可以使用ArrayList的指定大小的构造方法或在添加大量元素之前使用ensureCapacity()方法预先指定较大的容量,以减少容量调整的次数。
另外,当从ArrayList中删除元素时,并不会立即缩小内部数组的容量。如果希望减少内存占用,可以使用trimToSize()方法来调整ArrayList的容量,使其与元素数量匹配。这样可以释放未使用的内存空间。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

雁过留声

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表