ArrayList
ArrayList相当于是一个动态类型的顺序表,底层是用数组实现的,所以适合随机的查找和遍历,不适合插入和删除
需要注意的几个点:
- 初始容量:
调用无参的构造方法时,默认会构造一个初始大小为10的数组,下面是部分源码:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有些小伙伴看到这块可能会有点疑惑,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
明明初始化是一个空数组,为什么要说构建了一个初始容量为10的空列表呢,见下:
//只是摘录部分源码 + 本可爱的理解
public boolean add(E e) {
//当调用add方法时,首先调用ensureCapacityInternal(int minCapacity)
//此时因为list里没有元素,所以size = 0,也就是说minCapacity = size + 1 =1,
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//由于minCapacity =1 < DEFAULT_CAPACITY,所以minCapacity=10;
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
ArrayList的扩容机制:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// 把当前数组的长度记为之前的容量大小
int oldCapacity = elementData.length;
// 新的容量 = 旧的容量 + (旧的容量>>1)
// 也就是说新容量 = 旧容量的1.5倍(>>相当于除以2)
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新容量是否小于最小需要扩容的容量,
//如果小于则将新容量设为最小需要的容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//然后检查新容量是否比数组最大的长度还大
//如果是则调用hugeCapacity方法继续确定新容量的大小
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 调用数组的copyOf(原始数组, 新数组长度)将原来的elementData内容复制到容量为newCapacity大小的新数组中,并将结果赋给elementData
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList
LinkedList 底层是不带头的双向链表,由于是用链表实现的,所以查找慢,但增删元素快
ArrayList和LinkedList区别:
ArrayList | LinkedList | |
---|---|---|
存储结构 | 连续空间 | 链式结构 |
是否支持随机访问 | 是 | 否 |
任意位置插入/删除元素的时间复杂度 | O(N) | O(1) |
是否需要扩容 | 在插入期间可能需要扩容(因为底层是连续的空间,空间一旦给好,那么大小就确定好了) | 不需要 |
应用场景 | 存储+大量访问元素 | 大量任意位置插入删除元素 |
Q: 他们两个的空间利用率谁高一些呢?
- 不能确定,因为:
- 单纯从存储空间的角度来看,ArrayList每个节点只需要存储元素就可以 ,而LinkedList除了要存储节点还要存储节点和节点之间的关系
- 但是插入期间ArrayList如果需要扩容,因为ArrayList扩容是按照1.5倍扩的,空间没有占满的话,他的利用率会低一点