zoukankan      html  css  js  c++  java
  • ArrayList扩容源码分析

    一、前言

      1.本文基于JDK1.8源码分析,会贴出涉及的相关数据结构及源码。

      2.为节省大家时间,先给出结论。

      1)ArrayList创建对象时,若未指定集合大小初始化大小为0;若已指定大小,集合大小为指定的大小;

      2)当第一次调用add方法时,集合长度变为DEFAULT_CAPACITY(也就是10)和集合长度size+1之间的较大值;

      3)集合初始化后再调用add,先将集合扩大为原来的1.5倍,如果仍然不够,新长度设为新集合长度大小;

    二、主要属性

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        private static final long serialVersionUID = 8683452581122892189L;
        
        private static final int DEFAULT_CAPACITY = 10;//默认初始化容量
    
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认空容量
    
        private static final Object[] EMPTY_ELEMENTDATA = {};//空实例
    
        transient Object[] elementData;//数组缓冲,将在添加第一个元素时扩展至默认容量
    
        private int size;//数组大小
    }

    三、扩容分析

      1.结论一:ArrayList创建对象时,若未指定集合大小初始化大小为0;若已指定大小,集合大小为指定的大小;

    //指定容量
    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;
        }

      2.结论二:当第一次调用add方法时,集合长度变为DEFAULT_CAPACITY(也就是10)和集合长度size+1之间的较大值;

         结论三:集合初始化后再调用add,先将集合扩大为原来的1.5倍,如果仍然不够,新长度设为新集合长度大小;

    //添加元素
    public boolean add(E e) {
            ensureCapacityInternal(size + 1);
            elementData[size++] = e;
            return true;
        }
    
    private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
            //判断是否第一次添加元素,是则取10与size+1间最大值
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            return minCapacity;
        }
    
    private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            //如果最小需要空间比elementData的内存空间要大,扩容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    //核心扩容方法
    private void grow(int minCapacity) {
            //获取原集合长度 
            int oldCapacity = elementData.length;
            //集合长度扩容为原长度的1.5倍
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            //如果扩容后仍小于添加集合的长度,新建集合长度为添加元素集合大小
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            //若预设值大于默认的最大值检查是否溢出 
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            //调用Arrays.copyOf方法将elementData数组指向新的长度为扩容后长度的内存空间
            elementData = Arrays.copyOf(elementData, newCapacity);
        }    
    
    //检查溢出
    private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }        

    四、结语

      本文主要记录ArrayList源码学习过程,只针对扩容方向性理解,有错误请指正,一起学习一起进步。

  • 相关阅读:
    HDU 2955 Robberies(01背包)
    HDU 2602 Bone Collector(01背包)
    HUST 1352 Repetitions of Substrings(字符串)
    HUST 1358 Uiwurerirexb jeqvad(模拟解密)
    HUST 1404 Hamming Distance(字符串)
    HDU 4520 小Q系列故事――最佳裁判(STL)
    HDU 2058 The sum problem(枚举)
    【破解】修改程序版权、添加弹窗
    HDU 1407 测试你是否和LTC水平一样高(枚举)
    HDU 1050 Moving Tables(贪心)
  • 原文地址:https://www.cnblogs.com/ghoster/p/12621020.html
Copyright © 2011-2022 走看看