美文网首页
ArrayList扩容

ArrayList扩容

作者: ZhiJunPan | 来源:发表于2019-07-10 14:40 被阅读0次
众所周知,ArrayList是基于数组实现的,而在使用的时候我们从未担心过它的容量问题,毫无疑问这部分工作在源码中进行维护以及实现了。

这篇文章做一个研究源码的记录,使用的jdk版本是jdk11(不同的jdk版本源码可能不同)
首先查看ArrayList的构造函数,有三种方式来初始化ArrayList,分别是指定容量,不指定容量,以及用集合来初始化。

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) { 
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

使用默认构造方法的时候,先初始化一个空的数组,而在第一次插入的时候,将其初始化为默认容量的数组,默认容量为10.

只有在add或者addAll的时候会触发扩容机制。
首先我们先来考虑第一次插入元素的情况,一下为add的源码:

 private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

    public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }

第一次插入的时候,size是0,数组长度也为0,这是需要执行grow方法,接下来我们进入grow方法:

  private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    private Object[] grow() {
        return grow(size + 1);
    }

可以看到grow将size+1作为最小需要内容传入重载的grow(int minCapacity)方法,这个方法返回数组拷贝,拷贝大小为newCapacity方法返回的内容。接下来进入newCapacity方法:

  private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

可以看到新容量是旧容量的1.5倍,如果扩容容量小于需要的容量,满足if条件,对比数组是否为空数组,如果是空的话,数组容量为默认容量和最小需要容量的更大值(防止空间不足,第一次插入情况),若不为空,直接返回所需要容量。不满足if条件的话,如果返回新容量大于最大数组容量,则使用hugeCapacity方法确认容量,超过数组容量最大值的话返回int最大值,否则返回数组容量最大值。单个非首次add的情况不会触发新容量小于最小需要容量的情况。hugeCapacity方法:

private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }

而使用addAll方法的时候,则可能触发该条件。
使用情况:

当add第1个元素时,oldCapacity 为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity 不比 MAX_ARRAY_SIZE大,则不会进入 hugeCapacity 方法。数组容量为10,add方法中 return true,size增为1。
当add第11个元素进入grow方法时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中return true,size增为11

相关文章

  • 讲讲ArrayList的扩容和什么是溢出感知代码

    ArrayList 的扩容分为主动扩容和自动扩容两种。主动扩容就是通过调用 ArrayList 提供的 ensur...

  • Java动态数组实现(模拟ArrayList)

    目标:手动实现一个动态数组,模拟ArrayList ArrayList会自动扩容,先来看一下ArrayList扩容...

  • ArrayList 扩容 Android Java 真的不一

    以前学java基础的时候 看过ArrayList的扩容机制 实现原理是下面这样 当时做的笔记ArrayList扩容...

  • ArrayList源码分析

    问题提出 ArrayList底层采用什么数据结构? ArrayList是如何扩容的? 频繁扩容导致性能下降如何处理...

  • ArrayList动态扩容机制

    以ArrayList中add方法,讲解ArrayList动态扩容机制 扩容判断每次增加元素时,用size+1计算出...

  • ArrayList动态扩容机制--源码解析

    ArrayList动态扩容机制--源码解析 阅读原文 首先我们通过一个具体的例子看一下ArrayList的扩容效果...

  • ArrayList扩容

    重要属性 初始扩容 如果容量从0到1,比如调用add(E e),会将数组elementData变成{obj,nul...

  • ArrayList扩容

    众所周知,ArrayList是基于数组实现的,而在使用的时候我们从未担心过它的容量问题,毫无疑问这部分工作在源码中...

  • ArrayList扩容

    参考:https://github.com/Snailclimb/JavaGuide/blob/master/do...

  • java集合类-2-List

    ArrayList 属性 普通方法 添加元素 扩容 扩容系数:1.5 查找 删除 不调整elementData,t...

网友评论

      本文标题:ArrayList扩容

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