美文网首页
ArrayList源码分析

ArrayList源码分析

作者: capo | 来源:发表于2017-08-28 21:41 被阅读33次

简书:capo
转载请注明原创出处,谢谢!

今天,我们分析下JDK8中ArrayList的源码,我们知道ArrayList是List接口的一个实现,是一个动态扩容的数组。那么它是怎样在我们添加元素时实现动态扩容的了?

这是数组定义的几个成员变量


image.png

首先我们调用数组的 add(E e) 方法时,这里我用的是一个重载的方法,第一个参数指的是要添加元素的下标,默认如果我们不提供这个参数的话是从数组的最后添加的。

public void add(int var1, E var2) {
        //检查数组下标
        this.rangeCheckForAdd(var1);
        //保证数组内部容量 插入数组位置往后移动一个位置
        this.ensureCapacityInternal(this.size + 1);      
        //旧的数组就会使用Arrays.copyOf方法被复制到新的数组中,现有的数组指向了新的数组
        System.arraycopy(this.elementData, var1, this.elementData, var1 + 1, this.size - var1);
        this.elementData[var1] = var2;
        ++this.size;
    }

Java会检查这个数组下标是否超过这个数组的长度或者下标小于0,如果是的话就抛出
IndexOutOfBoundsException异常

 private void rangeCheckForAdd(int var1) {
        if(var1 > this.size || var1 < 0) {
            throw new IndexOutOfBoundsException(this.outOfBoundsMsg(var1));
        }
    }

如果数组元素等于默认空数组的话,那么数组插入数组索引下标会进行一个取最大值的操作

private void ensureCapacityInternal(int var1) {
       //如果添加的这个元素 == 默认的空数组的第一个元素
        if(this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            var1 = Math.max(10, var1); //在数组初始容量和数组的下标中取一个最大值
        }
        
        //明确保证数组的容量
        this.ensureExplicitCapacity(var1);
    }

为了明确保证数组容量序列化计算

private void ensureExplicitCapacity(int var1) {
         //反序列化计算器加 1 
        ++this.modCount;
        //如果要指定添加元素的下标位置 > 数组长度  此时就要扩容
        if(var1 - this.elementData.length > 0) {
            this.grow(var1);
        }

    }

计算新数组的长度=原始数组的1.5倍

private void grow(int var1) {
             
        int var2 = this.elementData.length;
        //新的数组长度 = 原始数组长度 + 原始数组 / 2
        int var3 = var2 + (var2 >> 1);
        //如果新的数组长度 < 要添加元素的位置
        if(var3 - var1 < 0) {
            var3 = var1;//新数组长度 = 添加元素的位置长度
        }
        
        //如果新的数组长度 > 2147483639 
        if(var3 - 2147483639 > 0) {
            var3 = hugeCapacity(var1); //就判断是否超过了JVM内存
        }

        this.elementData = Arrays.copyOf(this.elementData, var3);
    }

判断这个新数组长度是否JVM内存分配的最大值

private static int hugeCapacity(int var0) {
        if(var0 < 0) {
            throw new OutOfMemoryError();
        } else {
            return var0 > 2147483639?2147483647:2147483639;
        }
    }

总结一下:

  • ArrayList底层是一个动态扩容的数
  • 数组的初始长度是10个单位
  • 如果指定了要添加元素的索引下标的话,如果这个数组元素默认初始空数组的话就取一个最小值(添加元素的下标索引)
  • 扩容后新数组的长度 = 原始数组长度 + 原始数组长度/2 (也就是原始数组长度的1.5倍)
  • 数组的长度不是没有上限的,如果超过2147483639就会报OOM

相关文章

网友评论

      本文标题:ArrayList源码分析

      本文链接:https://www.haomeiwen.com/subject/ntqndxtx.html