(2.1.8.6)ArrayList原理分析(重点在于扩容)

xiaoxiao2021-02-28  77

成员变量

首先,ArrayList定义只定义类两个私有属性:

/** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size;

可知:elementData存储ArrayList内的元素,size表示它包含的元素的数量(不是指容量)。

注意:elementData用transient修饰,这表明当持久化ArrayList对象时,并不会保存它。

add()

ArrayList是基于数组实现的,添加元素时,将某个位置的值设置为指定元素即可,但数组容量不够,如何扩容呢?

我们提供具体的方法来分析:

add方法:

// 将指定的元素添加到此列表的尾部。 public boolean add(E e) { ensureCapacity(size + 1); //判断容量是否足够,不够就扩容 elementData[size++] = e; return true; }

那么扩容的核心在于ensureCapacity方法

ensureCapacity方法:

public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { //size+1即添加后的长度,判断如果添加,会不会过长 Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //1.5倍扩容 if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); //将老数组拷贝一份到新数组 } }

可知:

每次添加前都会判断是否会过长,会,则先扩容每次扩容都是1.5倍扩容,其实是1.5倍+1。老数组通过Arrays.copyOf()拷贝一份到新数组

那么问题来了,每次扩容都是1.5倍是否会造成较大的空间浪费?

是的,所以建议在构造ArrayList实例时,就预估大小并指定其容量,以避免数组扩容的发生。或者根据实际需求,直接调用ensureCapacity方法来手动增加ArrayList实例的容量。

转载请注明原文地址: https://www.6miu.com/read-96832.html

最新回复(0)