ArrayList底层源码分析

ArrayList底层源码分析

image-20240305143529677

底层原理

  • 创建使用ArrayList<>()创建空对象的时候,会在底层创建一个长度为0的数组。该数组的名称为elementData,定义变量size

    • size变量有两层含义
      • ① 表示元素的个数,也就是集合的长度
      • ② 表示下一个元素的存入位置
  • 添加第一个元素之后,size++,同时底层会创建一个新的长度为DEFAULT_CAPACITY=10的数组

  • 扩容机制1:

    • 当存满的时候,会创建一个新的数组,新数组的长度是原来的1.5倍,也就是长度为15。再把所有的元素拷贝到新数组中。如果继续添加数据,这个长度为15的数组也满了,那就会继续按照相同的方式扩容1.5倍。
  • 扩容时机2:

    • 当使用例如addAll()这样的方法一次性添加多个数据,扩容1.5倍的方法不够用时,则以扩容的实际大小为准。

    成员变量:

private static final int DEFAULT_CAPACITY = 10;

private static final Object[] EMPTY_ELEMENTDATA = {};

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

transient Object[] elementData; 

private int size;

构造方法:

//无参构造器,最开始创建的是空数组,当添加第一个元素时初始化容量为10。
public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//指定初始化容量,为0的话则创建空数组。
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中。
public ArrayList(Collection<? extends E> c) {
	Object[] a = c.toArray();
	if ((size = a.length) != 0) {
		if (c.getClass() == ArrayList.class) {
			elementData = a;
		} else {
			elementData = Arrays.copyOf(a, size, Object[].class);
		}
	} else {
		// replace with empty array.
		elementData = EMPTY_ELEMENTDATA;
	}
}

add方法

  • add(E e):直接在ArrayList尾部追加元素
  • add(int index, E element):在指定index位置追加元素
public boolean add(E e) {
	//记录结构上被修改的次数
	modCount++;
	add(e, elementData, size);
	return true;
}

private void add(E e, Object[] elementData, int s) {
	//如果当前数组长度等于ArrayList容量则扩容
	if (s == elementData.length)
		elementData = grow();
	elementData[s] = e;
	size = s + 1;
}

public void add(int index, E element) {
	//检查下标是否越界
	rangeCheckForAdd(index);
	modCount++;
	final int s;
	Object[] elementData;
	//如果当前数组长度等于ArrayList容量则扩容
	if ((s = size) == (elementData = this.elementData).length)
		elementData = grow();
	//把index位置及其后的元素向后移动一位
	System.arraycopy(elementData, index,
					 elementData, index + 1,
					 s - index);
	elementData[index] = element;
	size = s + 1;
}

grow()方法

private Object[] grow(int minCapacity) {
	int oldCapacity = elementData.length;
	if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		//获取新容量大小
		//oldCapacity右移一位即是原长度的一半,ArraysSupport.newLength方法选择minCapacity - oldCapacity或oldCapacity >> 1较大的一方与oldCapacity相加。
		int newCapacity = ArraysSupport.newLength(oldCapacity,
												  minCapacity - oldCapacity, /* minimum growth */
												  oldCapacity >> 1           /* preferred growth */);
		//将之前元素迁移到新数组,返回按照新容量扩容后的数组
		return elementData = Arrays.copyOf(elementData, newCapacity);
	} else {
		//如果容量为0,则按照默认容量创建一个数组。
		return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
	}
}

private Object[] grow() {
	return grow(size + 1);
}

添加一个元素源码分析

第一次添加数据

添加多个元素源码分析

第11次添加数据

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值