ArrayList | 程序员的生活记录
后端
833 ·
0 ·
2022-03-23 01:06:15
最新编辑时间: 2022-05-24 10:46:32
最新编辑原因:
我是"第一次正式地"在网上写文章,仅仅是因为想在2022年开始改变,不能和前几年一样了,除了"家-公司"两点一线的生活就没有其他的事情了。

所以在这里先从简单的开始,即从ArrayList开始。一来是刚开始,找找写文章的感觉; 二来是为了不打击自己,先找自己能把握的住的内容写,后面再慢慢的深入

1. ArrayList的使用场景

在业务开发中ArrayList的使用非常频繁,比HashMap使用的都多。例如我们查DB的时候,使用List来接收查询的结果,又比如我们把一组相同类型的数据放在一起时会使用等等,总之ArrayList凭借它简单易用的特点,常常被程序员拿来使用。

 

2.原理及分析

既然ArrayList这么常用,那么我们就从最基本的`add方法开始说起。

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

上面是ArrayList的add方法,可以看到非常简单! 仅仅只有2步:

  1. 确保有足够的容量

  2. 直接将元素追加到末尾

第一步给我们总了很多操作,所以我们才能愉快的往集合里面丢数据,不用管太多。这都是ArrayList辛辛苦苦帮我们默默的承受了。接着,从第二步我们明显的可以看出ArrayList的底层其实是数组,往ArrayList里面丢元素,它就把元素追加到最后的位置。

那么小伙伴到这里可能有疑问了,ArrayList到底做了什么我们才可以一直往里面塞数据? 这个问题很好,和我一样,哈哈,如果是我,我也会这样问,哈哈,这让我想起了自己初中和高中的意见小事,就是我追着数学老师问1+1为什么等于2的问题了。我不能回答1+1为什么等于2,但是我可以和你一起看看ArrayList到底在幕后做了什么可以让我们愉快地一直添加数据。那么,让我们看到第一步的方法ensureCapacityInternal(size + 1):

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

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

ensureCapacityInternal调用了ensureExplicitCapacity方法,ensureExplicitCapacity里面做了一个判断,就是即将要加入的元素如果加进来后它的长度如果大于数组的长度则需要grow(增长),就是扩容。因为有了扩容,所以我们才可以一直愉快的塞数据哈哈

minCapacity看代码是add方法中第一行 ensureCapacityInternal(size + 1) 中的size+1即 即将要占用的位置

那么说到了扩容,那么ArrayList是如何扩容的呢?其实看看grow方法就知道了

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    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);
}

可以看到经过一系列的计算(主要是计算扩容到多少合适), grow方法使用一个Arrays.copyOf,即数组复制完成了扩容,对,就是这么简单,建一个数组,然后将旧的数组数据复制上去就结束了。

 

3.总结

其实ArrayList稍微值得一看的就是add方法。其他的点其实很简单,都可以推理出来。因为我们知道ArrayList的底层是数组,而数组在内存中是一段连续的空间,所以ArrayList的遍历特别快,不需要寻址(就是找地方),只要依次往下遍历即可。那么说到这里问题也显而易见,如果元素在数组的最后面,那么找到它的耗时就很长,所以这也是ArrayList的缺点。


仓库地址: https://github.com/yangrunkang/programmer-life-record

本作品系原创,采用《署名-非商业性使用-禁止演绎4.0 国际》许可协议.转载请说明出处
本文链接:https://www.upupor.com/u/22032117348575142912 复制

无内容

推荐阅读