JDK源码之ArrayList

介绍

ArraryList继承了List接口,它可以改变大小,支持快速访问,并且它的项可以是null

public class ArrayList<E> extends AbstractList<E>  
 implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
...
}

数据结构

ArrayList的底层的数据结构是一个 「Object[] elementData」 数组。

通过 「int size」 变量来记录ArrayList中当前包含的元素个数。当通过 「add」 方法向ArrayList添加元素时,如果添加成功size会自动+1。使用「remove」方法删除元素时,size会自动-1。

在使用ArrayList的无参构造方法时,elementData会被赋值为 「DEFAULTCAPACITY_EMPTY_ELEMENTDATA」,此时是一个空数组,这就意味着只要向ArrayList中添加元素,它就需要进行[[#扩容]],此时,会重新创建一个大小为10的新数组。

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

扩容

对于ArrayList的扩容,分为两种场景:

  • 通过无参构造函数创建后,第一次添加元素

  • 已有元素的扩容

创建后第一次添加

创建后第一添加元素,此时会创建一个大小为10的新数组。

已有元素扩容

计算现有数组的大小length,并在此基础上增加50%,也就是 3/2*length 作为newCapacity与minCapacity比较,两者相减为负,则newCapacity取minCapacity的值。

然后再用newCapacity与MAX_ARRAY_SIZE比较,重新结算newCapacity的值。

newCapacity的最大值为Integer.MAX_VALUE。

MAX_ARRAY_SIZE=Integer.MAX_VALUE - 8;

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);  
}  
  
private static int hugeCapacity(int minCapacity) {  
	if (minCapacity < 0) // overflow  
		throw new OutOfMemoryError();  
	return (minCapacity > MAX_ARRAY_SIZE) ?  
			Integer.MAX_VALUE :  
			MAX_ARRAY_SIZE;  
}

这里有个很有意思的点就是重点看 int newCapacity = oldCapacity + (oldCapacity >> 1),此时的newCapacity是通过相加计算出来的,它会存在「越界」的情况,也就是说newCapacity本身就可能是负值。

性能

对于ArrayLIst来讲,如果是使用index查元素的话,时间复杂度就是O(1)。如果使用查元素在ArrayList中的索引位置,时间复杂度就是O(n)。

遍历

  • for遍历

for (int i = 0; i < arr.size(); i++) {
	Object item = arr[i];
}
  • for倒叙遍历

for (int i = arr.size() - 1; i >= 0; i--) {
	Object item = arr[i];
}
  • for each

for (Object item : arr) {
	// ...
}
  • Iterator迭代器

Iterator it = arr.iterator();
while (it.hasNext()) {
	// it.next();
}
  • forEach,1.8支持

arr.forEach(item -> {
	// ...
});

遍历中删除

「不可以使用正序遍历删除」,如果使用ArrayList的for正序遍历,在删除元素的过程中,会产生数据移位,导致删除不全的问题。

多线程

ArrayList在多线程中的线程不安全主要是在多线程中对ArrayList进行修改的过程中 size++size-- 是非原子性的,并且不具备内存可见性,同时ArrayList中没有锁的存在。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值