ArrayList的扩容机制以及常用方法源码分析

六眼飞鱼酱① 提交于 2020-01-15 09:05:05

一直想记录自己的学习过程,但始终没有付出实际行动,说来惭愧

感谢您的关注,持续更新,欢迎留言交流~

前言:

虽然面试我们通常是讲ArrayList和数组的区别,但小编觉得,我们有必要去了解一下ArrayList,在我们日常开发上,ArrayList也算得上是一种常用的集合了,接下来就和小编一起来扯下淡吧~

话不多说,直接上源码,以下源码基于JDK1.8 让我们先来看看 

ArrayList list = new ArrayList();
list.add("小编是个秃顶的大叔~");
    // 默认为 0
    private int size;

    /**
     * Appends the specified element to the end of this list.
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        // size[0] + 1 当作参数传入方法 
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
    }

接下来我们来看看ensureCapacityInternal()方法

思路:其实就是判断数组是否初始化,未初始化赋初始值 10 

    // transient是用来反序列化的
    transient Object[] elementData; 

    // 定义一个空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    // 默认容量为 10
    private static final int DEFAULT_CAPACITY = 10;

    /**
    * minCapacity:当前存放值的下标 + 1(size + 1) 
    */
    private void ensureCapacityInternal(int minCapacity) {
        // 判断elementData是不是默认的空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 取得两个参数中的最大值:DEFAULT_CAPACITY --> 10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        // minCapacity = 10
        ensureExplicitCapacity(minCapacity);
    }

接下来我们看看ensureExplicitCapacity()方法:

扩容的大致整体思路:

1.判断这个集合是否达到扩容的标准

2.若扩容之后的长度比插入的这个当前的容量还小,则扩容的容量 = 当前容量(minCapaccity)

3.如果扩容的大小比ArrayList的最大长度还大  如何处理【hugeCapacity方法】

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//modCount是记录修改次数 与线程安全有关系

        // 判断是否达到扩容的条件: 当前容量 > 数组长度
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // 赋值以前的容量
        int oldCapacity = elementData.length;

        // 当前容量为:old容量 + (old容量 / 2) 对于>>不懂的,小编后边会专门写一篇博客
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        // 扩容后的容量 小于 当前容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;

        // 扩容后的容量 大于 arraylist最大容量时
        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);
    }

// 小编觉得很有必要讲一下这个方法:扩容之后大于ArrayList的最大容量执行的hugeCapacity方法

有这么几个疑问:

1.为什么ArrayList的最大数组大小(MAX_ARRAY_SIZE)是:Integer.MAX_VALUE - 8?

2.为什么Integer.MAX_VALUE用0x7fffffff表示?

3.如果当前容量 大于 最大容量则赋值数组长度为Integer.MAX_VALUE,明明已经大于最大容量了?

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;

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

第一个问题:ArrayList的最大数组大小为什么是Integer.MAX_VALUE - 8?

刚开始小编也是到处找资料说是数组需要8 bytes去存储它自己的大小,开始小编觉得这个回答有些敷衍,直到用翻译工具截图翻译,这才解释了源码上这段可恶的英文,偶买噶,无形之中就暴露了小编的英文水平,请替我保密~~,哈哈哈哈哈哈

第二个问题:Integer.MAX_VALUE 为什么用0x7fffffff代表?

ox代表是16进制 7fffffff才是16进制的值,简单的说就是方便运算,计算器能理解的东西,我们不一定能理解。详细可自行Google一下或找本基础教材翻一下。

第三个问题:Integer.MAX_VALUE就是一个最大最大的上线,再大也不能比天王老子Integer的最大值大

关注小编,点个赞留个评论也是对小编莫大的支持,谢谢帅锅

后面持续更新,地中海发型尚未形成,小编仍需努力。。。。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!