LinkedList简介:
LinkedList底层是基于双向链表实现的,它是线程安全的,相对于ArrayList查找速度较慢,插入删除速度较快。
源码分析:
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;
}
}
顾名思义类名就是节点的意思,不用多说,next和prev引用同样也是Node对象。next指向下一个节点,prev指向上一个节点。所以可以确定LinkedList就是基于双向连接实现的。
add()方法源码分析:
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
//看方法注释,我们可以看到是将该元素添加到此链表的end,返回true
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
//首先取出last节点,last默认为null
final Node<E> l = last;
//创建节点,newNode 节点的prev 指向l,next=null
final Node<E> newNode = new Node<>(l, e, null);
//让last指向newNode
last = newNode;
//如果链表为null的话则first也指向newNode,此时链表只有一个节点first和last都指向同一个节点
//如果链表部位null,只需要将last的next指向这个newNode就行了,这样就形成了双向链表
if (l == null)
first = newNode;
else
//l节点的下一个节点指向newNode(本来l是最后一个节点,创建newNode后newNode就是最后节点)
l.next = newNode;
//最后size++
size++;
modCount++;
}
每添加一个元素时首先创建节点,节点的prev 值指向最后的节点。节点创建完后,将该节点设置为最后的节点,并且设置原来的末尾节点的next指向该节点。
get()方法解析:
public E get(int index) {
//判断是否越界,是抛出异常
checkElementIndex(index);
return node(index).item;
}
/**
*该方法是根据下标找到指定的节点
**/
Node<E> node(int index) {
//index小于size的一半则从头开始找,size >> 1 算术运算符等于size除2
if (index < (size >> 1)) {
//获取第一个节点
Node<E> x = first;
//循环历遍直到获取index指向的节点
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
get()方法会先执行checkElementIndex()判断下标是否越界,node()方法根据二分查找法找到我们指定的节点然后返回节点,最后get()返回节点的item,就是我们的内容。
remove()方法解析:
public E remove(int index) {
//判断是否越界,是抛出异常
checkElementIndex(index);
return unlink(node(index));
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
/**
*该方法是根据下标找到指定的节点
**/
Node<E> node(int index) {
//index小于size的一半则从头开始找
if (index < (size >> 1)) {
//获取第一个节点
Node<E> x = first;
//循环历遍直到获取index指向的节点
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
/**
*该方法删除节点
**/
E unlink(Node<E> x) {
// 获取的内容
final E element = x.item;
// 下个节点
final Node<E> next = x.next;
// 上个节点
final Node<E> prev = x.prev;
//prev == null说明该节点是第一个节点
if (prev == null) {
//直接把first 指向它的下一个节点
first = next;
} else {
//把它上一个节点的next值指向它的下一个节点
prev.next = next;
x.prev = null;
}
//next == null说明该节点是最后一个节点
if (next == null) {
//直接把last指向它的上一个节点
last = prev;
} else {
//把它下一个节点的prev值指向它的上一个节点
next.prev = prev;
x.next = null;
}
x.item = null;
// 链表长度减一
size--;
modCount++;
return element;
}
删除时先调用checkElementIndex()判断是否越界,是则抛异常。继续往下走调用node()方法,该方法使用二分查找法从头节点或者尾节点开始历遍整个链表找到指定的节点,然后返回。接着使用找到的节点作为参数调用unlink()方法。
LinkedList总结:
1.LinkedList底层是基于双向链表实现
2.LinkedList也是非线程安全的
3.LinkedList相比于ArrayList查找速度较慢,但插入和删除速度较快。
LinkedList实现线程安全:
List<String> linkedList = Collections.synchronizedList(new LinkedList<String>())