• ArrayList源码分析


    ArrayList源码分析

    底层数据结构:Object类型数组:Object[ ] elementData

    一、JDK 7主体源码

    步骤及其源码底层实现

    1.创建一个ArrayList对象

    ArrayList list = new ArrayList();	//底层创建了长度是10的Object[] 数组elementData
    

    底层实现ArrayList.java

    private transient Object[] elementData;
    

    第一步:调用无参构造器

        public ArrayList() {
            this.(initialCapacity:10);	//调用本类当中的重载构造器
        }
    

    第二步:this.(initialCapacity:10);调用本类当中的重载构造器

        public ArrayList(int initialCapacity) {
            super();
            if(initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity]	//初始化数组,容量为10
        }
    

    2.添加数据,add()方法

    list.add(1);
    ...
    list.add(11);	                //elementData[0] = new Integer(1)
    				//如果此次的添加导致底层elementData数组容量不够,则扩容。
    				//默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中
    

    底层实现ArrayList.java

    第一步:调用add( )

    public boolean add(E e) {
            ensureCapacityInternal(size + 1);          //确认容量是否够	size:代表已经添加了几个,初次为0
            elementData[size++] = e;		   //添加操作
            return true;
        }
    

    第二步:调用ensureCapacityInternal(),确认容量是否够

    private void ensureCapacityInternal(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)	                //minCapacity即size + 1,elementData.length为10
                grow(minCapacity);						//扩容
        }
    
    • 扩容:当添加第11个元素时,size为10,size+1也就是minCapacity为11,此时if条件:minCapacity - elementData.length > 0

    成立,于是调用grow()方法进行扩容。

    grow()

    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;					//初始容量:10
            int newCapacity = oldCapacity + (oldCapacity >> 1);			//默认扩容为原来的1.5倍,第一次扩容为15
            ...
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    

    elementData = Arrays.copyOf(elementData, newCapacity);

    原来容量为10的数组elementData需要被重新赋值为容量为15的数组,并且将原来的数组元素复制到新数组中

    结论

    建议开发中使用带参构造器ArrayList arrayList = new ArrayList(int capacity);这样可以避免扩容。

    二、JDK 8中ArrayList的变化

    1.创建一个ArrayList对象(没有创建长度是10的Object[] 数组)

    ArrayList list = new ArrayList();	//底层Object[] elementData初始化为{},并没有创建长度为10的数组
    

    底层实现ArrayList.java

    public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;	//指定了一个常量
        }
    
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};	//这里什么都没有 长度为0
    

    这里不像JDK 7那样在创建对象时就将数组实例化,从时间和占用内存(节省)上来说,这种方式较好一些

    2.添加数据,add()方法

    list.add(1)	//第一次调用add()时,底层才创建了长度为10的数组,并将数据1添加到elementData[0]
    ...
    

    底层实现ArrayList.java

    第一步:第一次调用add( )

    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    

    第二步:调用ensureCapacityInternal(),确认容量是否够

    0private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
    

    第三步:调用calculateCapacity()

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {	                        //第一次调用add()时,该条件成立
                return Math.max(DEFAULT_CAPACITY, minCapacity);		                //默认容量DEFAULT_CAPACITY为10
            }										//minCapacity即size+1=1
            return minCapacity;								//10
        }
    

    第四步:调用ensureExplicitCapacity()

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)		//minCapacity:10	elementData.length:0
            grow(minCapacity);				//10
    }
    

    第五步:调用grow()

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;				//0
        int newCapacity = oldCapacity + (oldCapacity >> 1);			//0=0+0
        if (newCapacity - minCapacity < 0)					//0-10<0
            newCapacity = minCapacity;					//newCapacity为10
        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);		//此时创建了长度为10的数组
    }
    

    三、总结

    ArrayList源码分析:

    1.jdk 7

    ArrayList list = new ArrayList();	
    
    1. 底层创建了长度是10的Object[] 数组elementData。
    list.add(1);
    ...
    list.add(11);	//elementData[0] = new Integer(1)
    
    1. list.add(11); --->如果此次的添加导致底层elementData数组容量不够,则扩容。默认情况下,扩容为原来的容量的1.5倍,同时需要将原有数组中的数据复制到新的数组中

    2.jdk 8中ArrayList的变化

    ArrayList list = new ArrayList();
    
    1. 底层Object[] elementData初始化为{},并没有创建长度为10的数组
    list.add(1)	
    ...
    
    1. 第一次调用add()时,底层才创建了长度为10的数组,并将数据1添加到elementData[0]。
    • 后续的添加和扩容操作与jdk 7无异。
    小结
    jdk 7当中的ArrayList的对象的创建类似单例的饿汉式,而jdk 8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创
    建,节省内存。
    相信自己,你能行!!!
  • 相关阅读:
    自学入门 Python 优质中文资源索引
    Crawlab Lite 正式发布,更轻量的爬虫管理平台
    一款被大厂选用的 Hexo 博客主题
    源码解读 Golang 的 sync.Map 实现原理
    探究 Go 语言 defer 语句的三种机制
    一道快速考察 Python 基础的面试题
    编写自己的 GitHub Action,体验自动化部署
    Python 2 与 3 共存了 11 年,新年就要和它道别
    30 年前的圣诞节,Python 序章被谱写
    文言文编程火了,可我完全学不懂
  • 原文地址:https://www.cnblogs.com/byd-hold-on/p/14039170.html
Copyright © 2020-2023  润新知