众所周知:
ArrayList:基于动态数组,连续内存存储,适合下标访问,再者就是它的扩容机制,因为数组长度固定,超出长度肯定需要扩容。
LinkedList:基于链表,可以存储在分散的内存中,插入和删除只需要更改一下指向,不适合查询,需要逐个遍历,无上限无序扩容。
下面我们对它们的方法进行逐个对比:
常用的add:
首先看下LinkedList中的add方法:
public boolean add(E e) { linkLast(e); return true; }
void linkLast(E e) { final Node<E> l = last; //这里和数组是有差别的,每次新增都是node对象,数组则不是 final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) //可以看出非常简单如果第一次增加只需要更改复制为 first = newNode; else //如果不是第一次增加采用尾插法插入最后位置即可 l.next = newNode; size++; modCount++; }
ArrayList中的add方法是什么样的呢?
public boolean add(E e) { //和linkedList的性能差别主要在这里,这里隐藏着数组的扩容机制(这里如果初始化值设置大些是不是就和linkedList无差别了) ensureCapacityInternal(size + 1); // Increments modCount!! //尾插入法这里性能不弱于linkedList,但是如果指定索引插入如add(index,e)则会触发数组的迁移,性能则大降 elementData[size++] = e; return true; }
上面我们比较了arrayList和LinkedList中add的差别下面看下各自的remove
还是先看linkedList:
public boolean remove(Object o) { //从时间复杂度上来看大家都是O(n) if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { //主要差别是在这里 unlink(x); return true; } } } return false; }
//删除操作这里直接改变指向就可以了
E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
看下ArrayList中的remove:
public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { //这里的时间复杂度也是O(n) for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { //和linkeList的性能差别主要在这里,存在数组的copy fastRemove(index); return true; } } return false; }
上面我们对ArrayList和LinkedList做了一个简单的对比,其实生产环境中我们arrayList是能够满足绝大部分场景的,如果对性能有极致的要求增删比较频繁是可以用linkedList解决
如果发现上面有什么问题还请及时更正 共同进步 共同成长 感恩 感谢
下面为个人公众号 欢迎一起交流