关于ArrayList与LinkedList的区别,我们会看到很多类似以下的结论
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
这很武断,让人知其然不知其所以然!
新增和删除
执行者:“萧叶,你知道ArrayList与LinkedList的区别吗?”
萧叶:“ArrayList、LinkedList新增和删除操作,LinedList比较占优势,因为ArrayList要移动数据。。。”
执行者:“我的数据放在数组末尾,不需要移动数据,为啥ArrayList会比LinkedList慢呢?”
萧叶:。。。
现在,我们来做以下实验:
List<Integer> array = new ArrayList<>();
List<Integer> link = new LinkedList<>();
long now = System.currentTimeMillis();
for (int i = 0; i< 10000000; i++){
array.add(i);
}
long after = System.currentTimeMillis();
System.out.println(after - now);
long now2 = System.currentTimeMillis();
for (int i = 0; i< 10000000; i++){
link.add(i);
}
long after2 = System.currentTimeMillis();
System.out.println(after2 - now2);
当插入的数量是100万次的时候
ArrayList耗时:75ms
LinkedList耗时:96ms
当插入的数量是1000万次的时候
ArrayList耗时:2.7s
LinkedList耗时:1.7s
以上数据会有波动,但是波动很小!
ArrayList的add(Object o)源码
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
---每次add会重新计算容量---
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
如果容量不够会调用到system的native方法
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
LinkedList的add(Object o)源码
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
其实不管是LinkedList还是ArrayList都有很多新增和删除方法,每一种删除或新增方法进行对比都不一样。
add(int index, E element)实验:
当插入的数量是1000万次的时候
ArrayList耗时:2.5s
LinkedList耗时:4.7s
更是接近两倍的速度,remove也一样!
add(Object o) 方法:
当List的size < 100万:
ArrayList新增速度大于LinkedList
当List的size < 1000万:
LinkedList新增速度大于ArrayList
原因分析:当数量过大,ArrayList调用的native方法进行copy,还要很大一段连续的内存,其时间成本比LinkedList大
add(int index, E element)、remove(int index, E element) 不论List的size多大,ArrayList的新增/删除速度都大于LinkedList。
其他区别:由于ArrayList底层是数组,所以ArrayList的内存地址是连续的,而LinkedList是引用,不用连续的内存空间。