ArrayList扩容分析

ArrayList扩容分析

ArrayList是一个实现List接口的可扩容数组。通过默认构造器创建容器时,该数组先被初始化为空数组,之后在首次添加数据时再将其初始化成长度为10的数组。

public ArrayList() {//首先初始化为一个空数组
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//首次调用add添加元素时会先进入ensureCapacityInternal()方法并且传入size+1,此时size为0
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  
	elementData[size++] = e;
	return true;
}

//进入ensureCapacityInternal()方法后
private void ensureCapacityInternal(int minCapacity) {
    //用于确保ArrayList的内部数组elementData有足够的空间来存储元素。
	ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

//随后进入calculateCapacity(),
private static int calculateCapacity(Object[] elementData, int minCapacity) {
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		return Math.max(DEFAULT_CAPACITY, minCapacity);//若初始大小小于10,则将size置为10
	}
	return minCapacity;
}

//ensureExplicitCapacity方法接受一个参数minCapacity,表示所需的最小容量。如果当前elementData的长度小于minCapacity,那么ensureExplicitCapacity方法会调用grow方法来分配一个新的数组,其长度至少为minCapacity
private void ensureExplicitCapacity(int minCapacity) {
	modCount++;//modCount是一个用来记录ArrayList结构变化次数的字段,每次添加或删除元素时,modCount都会增加。是ArrayList的一个同步机制,用于防止并发修改异常。
	if (minCapacity - elementData.length > 0)
		grow(minCapacity);
}

也可以使用有参构造器来创建容器,并通过参数来显式指定数组的容量。

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);
	}
}

如果向ArrayList中添加数据会造成超出数组长度限制,则会触发自动扩容将旧数组中的数据拷贝到新数组里,而新数组 的长度为原来长度的1.5倍,适用于快速查找匹配场景。

ArrayList扩容机制:

private void grow(int minCapacity) {
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if (newCapacity - minCapacity < 0)
		newCapacity = minCapacity;
	if (newCapacity - MAX_ARRAY_SIZE > 0)
		newCapacity = hugeCapacity(minCapacity);
	elementData = Arrays.copyOf(elementData, newCapacity);
}
//代码int newCapacity = oldCapacity + (oldCapacity >> 1);中,oldCapacity >> 1表示将oldCapacity的二进制位全部右移1位。由于整数除法的向下取整特性,这相当于将oldCapacity除以2并取整数部分。
//这行代码的含义是:新的容量是旧的容量加上旧容量的一半。这是一种常见的动态扩容策略,用于在不增加太多内存的情况下满足容量的增长需求。

不过ArrayList没有缩容机制, 但是ArrayList提供trimToSize()方法,它的作用是将ArrayList的容量调整为当前元素的数量。当调用此方法时,如果ArrayList的当前长度小于内部数组的长度,则会创建一个长度与元素数量相符的新数组,并将元素复制过去,释放多余的内存。

public void trimToSize() {
	modCount++;
	if (size < elementData.length) {
		elementData = (size == 0)?EMPTY_ELEMENTDATA:Arrays.copyOf(elementData,size);
	}
}

这样做可以确保ArrayList不再持有多于实际需求的外部内存,有助于内存优化

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ArrayListJava中常用的动态数组实现,它可以根据需要动态地增加或缩小数组的大小。当ArrayList中的元素数量超过了初始容量时,ArrayList会自动扩容,以便能够存储更多的元素。下面我们来看一下ArrayList扩容的源码实现。 在ArrayList中,扩容是由ensureCapacity方法实现的。当元素数量超过了数组容量时,该方法会调用grow方法来扩容数组。 ``` 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) { // 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); } ``` 首先,ensureCapacityInternal方法会调用ensureExplicitCapacity方法,该方法会检查是否需要扩容,并在需要时调用grow方法。 grow方法会首先计算新的数组容量,它的计算方式是将原来的容量增加一半。然后,grow方法会检查新容量是否大于最大数组容量,如果是,则调用hugeCapacity方法来返回一个足够大的容量值。最后,grow方法会调用Arrays.copyOf方法来将原来的数组复制到新的数组中。 需要注意的是,在进行扩容操作时,ArrayList会创建一个新的数组,并将原来的元素复制到新的数组中。这个过程会占用一定的时间和空间,因此,在使用ArrayList时,应该尽量避免频繁地进行扩容操作,以提高性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值