欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

简单复习一下ArrayList的扩容原理

程序员文章站 2022-09-28 12:20:54
刚刚跟几个好朋友喝完小酒回家,简单大概复习一下ArrayList的扩容原理,由于头有点小晕,就只大概说一下扩容的原理哈; 首先ArrayList实现了List接口,继承了AbstractList,大家都知道底层是由数组实现的,但是我们都知道数组是不会增的,那么ArrayList是如何自增扩容的呢? ......

刚刚跟几个好朋友喝完小酒回家,简单大概复习一下arraylist的扩容原理,由于头有点小晕,就只大概说一下扩容的原理哈;

首先arraylist实现了list接口,继承了abstractlist,大家都知道底层是由数组实现的,但是我们都知道数组是不会增的,那么arraylist是如何自增扩容的呢?

我们直接看它的add方法源码

    public boolean add(e e) {
        ensurecapacityinternal(size + 1);  // increments modcount!!
        elementdata[size++] = e;
        return true;
    }

    private void ensurecapacityinternal(int mincapacity) {
        if (elementdata == defaultcapacity_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) {
        int oldcapacity= this.elementdata.length;
        int newcapacity= oldcapacity + (oldcapacity >> 1);
        if (newcapacity - mincapacity < 0) {
            newcapacity = mincapacity;
        }
 
        if (newcapacity - max_array_size > 0) {
            newcapacity = hugecapacity(mincapacity);
        }
 
        this.elementdata = arrays.copyof(this.elementdata, arg2);
    }

size是当前集合拥有的元素个数,从源码看出,调用了ensurecapacityinternal来保证容量问题,传进去的参数是size+1,保证集合+1之后能够存储下一个数据。

default_capacity是arraylist定义的静态常量10;

判断elementdata是否是空数组,如果是则取一个较大的值;

接下来modcount++,这个值说过的,在保证fail-fast机制的时候协助使用的,用于判断集合的结构是否发生了变化;

新增元素后的长度值减去当前的容量值是否大于0,这里就是判断是否需要扩容的关键方法;

新长度 = 原长度 + 原长度右移以为位运算   ->   新长度 = 原长度 + 0.5倍原长度

如果新长度还是小于集合所需最小长度,则把最小长度赋值给新长度;而不进行扩容了;

如果新长度超过了最大的容量,则调用hugecapacity方法,这个方法里面判断,源码是一个三元运算:(最小所需长度 > max_array_size) ? integer.max_value : max_array_size;

其实说白了就是调用arrays.copyof方法,讲原数组复制到一个新的大容量数组;