ArrayList集合深度解析及其使用优化

ArrayList集合

(以下均使用jdk1.8)


ArrayList集合底层数组的创建和扩容机制:

① 通过源码中查看到elementData字段是ArrayList用来存储的底层数组。

在这里插入图片描述

在这里插入图片描述


② 所以只要我们获取到当前ArrayList类中该字段的值就可以知道该集合当前底层数组的长度

public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();

        //获取类对象
        Class clazz=arrayList.getClass();

        try {
            //获取类中elementData字段
            Field field=clazz.getDeclaredField("elementData");
            
            //进行爆破,获取权限
            field.setAccessible(true);
            
            //将对象传入,获取该字段当前的值
            Object[] obj=(Object[])field.get(arrayList);
            
            //打印底层数组的长度
            System.out.println(obj.length);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

③ 测试后的结果

1、当只是对集合进行初始化,而不添加任何元素的时候,集合的底层数组长度为0

2、当给集合添加 1 个元素,集合底层数组长度扩容10

3、当给集合添加 10 个元素,集合底层数组长度还是10

4、当给集合添加 11 个元素后,集合扩容为15,呈1.5倍增长

5、当给集合添加 16 个元素后,集合扩容为22,还是原数组的长度的1.5倍

在这里插入图片描述

在这里插入图片描述




三个构造方法

① 空参

初始化一个空的数组。

在这里插入图片描述


② int类型参数

在这里插入图片描述

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {	//如果参数大于 0 则创建参数大小的底层数组 等待扩容
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {	//如果参数等于 0 则创建一个空的底层数组 等待扩容
            this.elementData = EMPTY_ELEMENTDATA;
        } else {	//否则抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
}

③ Collection类型参数

将传入的Collection构建为一个集合。

Collection是List、Set、Queue的父接口,是单列集合的老大。也就是说,传入的可以是List集合,也可以是Set、Queue集合的子类。它通过迭代器返回的顺序构建一个ArrayList集合。





优化ArrayList

了解了ArrayList的创建机制,就要想办法优化它。

如果我们要在集合中添加一百万个数据,它只能是通过每次扩容1.5倍,每次将原数组数据放入新的数组,很明显非常消耗资源。

解决方式:

① 构造方法

在构造ArrayList时传入一个整型,就会直接构造一个该长度的集合,避免一直扩容造成的资源浪费。

② 使用普通方法

还可以使用ensureCapacity(int minCapacity)方法。参数为 扩容为目标大小。

如果要加入大量的数据,这种方式可以比传统方式快10倍以上,加入数据越多,越明显。

    public void ensureCapacity(int minCapacity) {
        //判断当前集合中是否已经有数据
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;
		//这里判断扩容必须大于10,否则不进行扩容,具体扩容多少,再调用下一个方法继续判断
        if (minCapacity > minExpand ) {
            ensureExplicitCapacity(minCapacity);
        }
    }

ensureExplicitCapacity方法:

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//对集合的操作次数+1,

        // 再次判断,扩容大小-当前容量 >0
        if (minCapacity - elementData.length > 0)
        	//调用扩容方法
            grow(minCapacity);
}

grow方法:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//位移运算,相当于*1.5
        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);
    }

使用该方法需要注意:

if( 扩容大小 > 10){
	if( 集合中是否已经有元素 ){
		if( 扩容大小 > 当前容量*1.5 ){
			扩容为目标大小
		}else{
            扩容为当前容量的1.5}
	}else{
        扩容为目标大小
    }
}


原创文章转载请注明出处谢谢

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二饭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值