ArrayList的扩容时机和扩容方式

ArrayList的扩容时机和扩容方式

    • ArrayList扩容机制简单介绍
    • ArrayList扩容机制详细介绍

大家好! 最近看了一下JAVA集合的相关底层实现原理,这里简单对 ArrayList的扩容机制 做一下简单介绍。本文是个人的简单理解,希望对大家有一定的帮助。

ArrayList扩容机制简单介绍

这里我简单介绍扩容机制的主要实现部分,对于一些理解能力很好的朋友,可以直接看这部分,后面的可以忽略:

  1. 扩容时机 ,ArrayList的扩容时机,主要看它底层的方法;
private void ensureExplicitCapacity(int minCapacity) {
     
        modCount++;  // 标记集合修改的次数

        // 主要在这也行代码
        /**
        * @minCapacity 添加元素后,集合的最小的容量
        * @elementData.length  实现集合的数组的长度
        */
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

主要判断所需的长度大小是否小于数组的长度,如果数组的长度比所需要的小,那么久进行扩容;

  1. 扩容方式, 在判断需要扩容的情况下,对数组进行扩容,下面来介绍扩容的主要代码;
private void grow(int minCapacity) {
     
        int oldCapacity = elementData.length;
        // 这是扩容的核心代码
        /**
        * oldCapacity >> 1 :表示数组的原来长度进行 除2操作
        * 	例如:oldCapacity = elementData.length = 10
        * 		二进制表示为:1010,向右以为后:0101 = 5
        * 总的来说:就是把原来的数组长度 *1.5
        */
        int newCapacity = oldCapacity + (oldCapacity >> 1);
     
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
       
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

这就是扩容方式的主要代码,但是,我个人觉得,实际上并不是按照1.5倍扩容,而是按照 位运算算出来的, oldCapacity + (oldCapacity >> 1),或者可以说是 1.5倍后向下取整;例如:原来的长度为15,1111 + 0111 = 22;扩容后的数组长度应该为22。

ArrayList扩容机制详细介绍

这部分是对上一部分做一个详细的介绍,如何在上面的部分,你已经看懂了,那么这部分你可不用在花时间看了。

  1. 扩容时机
    扩容时机的话,我们主要从add方法入手,最后判断是否扩容是在ensureExplicitCapacity()方法,下面一个个看:
	/**
	* 添加元素到集合的末尾
	*/ 
    public boolean add(E e) {
     
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
	// 这里的 minCapacity = size + 1 
	// 可以理解为,如果要添加这个元素,集合需要的大小
	private void ensureCapacityInternal(int minCapacity) {
     
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
	// 主要判断 集合需要的最小的大小,如何是初始化,则为10,反之则为 size + 1
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
     
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    // 这里 判断是否需要扩容
	private void ensureExplicitCapacity(int minCapacity) {
     
        modCount++;

        // 底层数组的长度>集合需要的最小大小 ?扩容:不扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

大家可以在ensureExplicitCapacity方法中看到,是否需要扩容的判断 if (minCapacity - elementData.length > 0)
总结:当添加元素后的集合大小(这个大小是理论上的,实际上还没有添加元素),比底层实现集合的数组的长度大的话,就进行扩容;
2. 扩容方式
扩容方式,主要分析grow这个方法

	private void grow(int minCapacity) {
     
        // 获取原来数组的长度
        int oldCapacity = elementData.length;
        // 数组长度变为原来的 1.5 倍(乘1.5倍后向下取整)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 扩容的大小 是否 还是小于 最小的集合大小  
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
       	// 这里判断的是,扩容是否 比 2 的30次还大     
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
            
        // 创建一个扩容后的新数组,并对新数组进行元素赋值
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

以上就是我对ArrayList源码查看,然后得出的一些结论,希望对大家有帮助,如果有错误,希望大家指出,我及时修改,以免误导大家。最后,大家在学习的时候,也可以通过DEBUG的方式,一遍遍跑源码,这样也会让自己对知识点理解更加深刻,不会说看完就忘。

你可能感兴趣的:(JAVA学习,java)