数组
![](https://img.haomeiwen.com/i27205827/2f254cb02ff0fade.jpg)
相信大家对数组都很熟悉,但是数组有一个很大的弊端,容量是固定的。
因此在不确定数据数量的场景使用起来会很不方便:声明大了浪费空间,声明小了数据存不下。
那么是否可以变更它的存储空间呢?
ArrayList
假设数组的基础长度是3,当想要插入第4个元素(array[3])时,可以考虑这样的算法:
1、重新申请一块连续的空间,空间大小为5。
2、将原来的数据依次复制到新的数组中
3、将第4个元素插入新数组相应的位置
这样,我们便可以摆脱数据长度的限制,放心的使用。ArrayList便是基于这种算法实现的。
![](https://img.haomeiwen.com/i27205827/8f02656224575af8.jpg)
ArrayList源码分析(JDK1.8)
1、ArrayList中存放元素的数组elementData,记录元素个数的变量size
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
// Android-note: Also accessed from java.util.Collections
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
2、扩容方案:
调用链:add() -> ensureCapacityInternal() -> ensureExplicitCapacity() -> grow()
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
// 获取原来的容量
int oldCapacity = elementData.length;
// 计算新的容量 = 老容量 + 老容量/2
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);
}
3、向指定位置添加元素
/**
* Inserts the specified element at the specified position in this
* list. Shifts the element currently at that position (if any) and
* any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
// 判断是否需要扩容
ensureCapacityInternal(size + 1); // Increments modCount!!
// 从index起,将元素向后移动一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 给index元素赋值
elementData[index] = element;
size++;
}
4、查询
public E get(int index) {
if (index < 0 || index >= this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
if (ArrayList.this.modCount != this.modCount)
throw new ConcurrentModificationException();
return (E) ArrayList.this.elementData[offset + index];
}
其他
1、由于ArrayList基于数组,所以查询效率相对较高,任何位置的元素查询效率一样
2、由于插入元素可能涉及到扩容、复制元素等操作,导致增加、删除元素会有时间损耗
网友评论