概述
LinkedList 的底层是链表,元数据是Node节点,每一个节点有一个前向指向prev,和后向指向next,以及存储了它自己的值。因此它的添加、删除效率很高,查询效率低。
ArrayList 的底层是数组,每一个ArrayList都有一个缓存的数组存储着这个列表中的数据,因为有index,根据下表在存储,所以查询效率高,但是添加和删除的时候,需要对列表中大部分数据的index进行操作,所以添加删除效率低
LinkedList
它里面有一个node内部类
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
默认的临时变量
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
查询
可以查询第一个
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
也可以查询最后一个
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
添加
在最前面添加
public void addFirst(E e) {
linkFirst(e);
}
让这个成为最前面的对象,并将之前的第一个对象的prev指向这个新对象
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
在最后面添加
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添加默认是在末尾添加
public boolean add(E e) {
linkLast(e);
return true;
}
也可以指定在那个index添加
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
这里默认是在index的前面添加
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
删除
删除第一个
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
其中unlinkFirst就是将第一个元素从列表中解除绑定
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
删除最后一个
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
其中unlinkLast是将最后一个元素从列表中解除绑定
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
删除一个对象
public boolean remove(Object o) {
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;
}
其中unlink就是解除这个对象的绑定
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;
}
需要对这个对象的前面的指向和后面的指向都指向null,并将它本身的值置为null,然后将这个对象原本的前指向直接指向后指向。
清空
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
将list中的值全部清空
浅克隆
@SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
List转数组
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
Arraylist
数组的默认初始化大小是10
private static final int DEFAULT_CAPACITY = 10;
初始化一个共享的空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};
初始化一个默认大小为默认初始化大小的空实例。当添加数组中的第一个数据后,EMPTY_ELEMENTDATA就转为
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
构造函数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
下面这个数组缓存了ArrayList中存储的数据
transient Object[] elementData;
每次扩展的容量,为原来的容量加上原来容量的一半(右移1位)。如果有一个指定的最小容量,扩展一半容量后的比指定的最小容量小,就以自定义的最小容量为准。如果扩展后的容量比指定的最大容量还要大,就是Integer对应的最大值。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
其中
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
显示最大值和Integer最大的值相差8。
浅克隆
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
List转数组
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
查询
底层就是返回的数组中的值
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
添加
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
首先确保数组的容量够大,不越界。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
如果是默认的一个空数组,那么取默认的10和当前size+1的最大值得到minCapacity,如果minCapacity比缓存数据长度大。则按照上面的grow规则进行扩充。
删除
删除序列,调用的就是System的arraycopy方法
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
删除对象,删除第一次遇到的这个对象。
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
java中的数组在定义后就不能修改长度了。可以直接修改数组中某个元素的值。但是新增和删除必须要新创建一个数组才能实现。
其中的System.arraycopy方法是jvm的一个native方法
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
删除某个index区间的值
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
清空list
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
后记
我在调用linkedList的getFirst方式时,一直没有这个方法。原来我一直习惯性写的代码是
List<Integer> linkedList = new LinkedList<>();
实际上写成
LinkedList<Integer> linkedList = new LinkedList<>();
就可以了,这是因为List中是没有这个方法的。同理对ArrayList一样,如果前面声明的是List,也不能调用到ArrayList中的特有方法。