美文网首页
ArrayList扩容

ArrayList扩容

作者: wtmxx | 来源:发表于2018-02-24 23:36 被阅读0次

重要属性

    //初次扩容(size为0)时的默认容量
   private static final int DEFAULT_CAPACITY = 10;

    //存在常量池的零值
    private static final Object[] EMPTY_ELEMENTDATA = {};

    //实际存储对象的数组,文档管他叫array buffer
   //容量就是指elementData的长度
    private transient Object[] elementData;
    
    //数组最大值是2147483639,不是2147483647的原因是
    //有些虚拟机在创建数组时会有头部信息
    //超过这个值会报OutOfMemoryError
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

初始扩容

  • 如果容量从0到1,比如调用add(E e),会将数组elementData变成{obj,null,null,null,null,null,null,null,null,null}
  • 如果容量从0到12(超过了DEFAULT_CAPACITY ),比如调用addAll(Collection<? extends E>c)添加一个长度为12的数组,那么elementData的长度就是12

超过10后的扩容

如果容量超过10,再次扩容时比较,至少需要的容量和1.5当前容量,取大值。至少需要的容量指实际元素的个数(size的值)。比如当前容量15,实际元素12,需要一次性添加4个元素,那么至少需要的容量是16,1.5当前容量是22,容量将变为22。

代码实现

//以下三个函数用来确认是否需要扩容
public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
   //计算扩容值的函数
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
   //分配容量的函数
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

trimToSize方法

    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }

由于扩容后会产生很多填充的null,这个方法可以讲这些null都去掉以节省内存,做法是调用一次copyOf方法创建一个新数组再把原来的拷贝进去。

总结

注意到copyOf方法会重新创建一个新的newLength长度的Object[],并调用native方法来将原数组复制到新的Object[]里,这个动作开销还是很大的。这也就是数组扩容逻辑的意义:尽量减少调用这个copyOf方法,从而提高效率。

相关文章

  • 讲讲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/hancxftx.html