java集合中的list源码分析
这里根据我的使用习惯分析几个常用的list
linkedlist
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
这里看到linkedlist实现了deque是一个双端链表,而且继承的也不是abstractlist抽象类。
public boolean add(E e) {
linkLast(e);
return true;
}
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;
}
上面就是我们常用的add和remove方法了,可以看出来这两个方法都是通过内部的private方法实现的,并且和之前分析的queue不同,没有使用到lock是一种线程不安全的方法。
而且有意思的是remove方法将object和null分开了。而不是在一个if中进行||这样的或判断,这样的话可能是减少了判断的次数在某种程度上加快了效率。
这里再看一下内部的link和unlink方法
/**
* Links e as first element.
*/
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++;
}
/**
* Links e as last element.
*/
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++;
}
/**
* Inserts element e before non-null Node succ.
*/
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++;
}
/**
* Unlinks non-null first node f.
*/
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;
}
/**
* Unlinks non-null last node l.
*/
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;
}
/**
* Unlinks non-null node x.
*/
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) {//这里判断成功说明目标node的上一个是first节点
first = next;//直接将first越过指向下一个,这样就讲一个node的引用清掉了
} else {//这里说明这个上一个节点不是头节点
prev.next = 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
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
private static final int DEFAULT_CAPACITY = 10;
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);
}
}
这个arraylist实现了randomaccess而没有实现deque,因为是数组实现所以可以根据index直接访问某一个element。
默认数组容量是10,而且我们也可以初始化实例对象时设置一个底层的数组大小
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;
}
上面是list的扩容方法可以看出来是以移位和arrays的copyof方法来实现的,也就是说每一次扩容都代表着要在底层创建一个新的数组来替换底层数组引用。这就代表了扩容的消耗随着list的内容变多而变大,所以在使用时最好实现设置一个大小,来减少扩容的次数。
vector
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
可以看出来vector和arraylist的接口是一摸一样的,而且内部也是数组实现。而且capacityIncrement这个属性是我们自己设置的扩容中的数组增长长度。
在vector中大部分的方法都是synchronized修饰的代码,是以实例对象本身来作为锁来实现线程安全的,不过我平常使用还是会使用arraylist这种线程不安全的然后再通过lock来实现同步。