1、特点
LinkedList集合实现了List接口,底层数据结构是一个双向链表,查询慢,增删快,线程不安全,效率高。
2、功能及源码
1)内部类
链表节点类
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;
}
}
2)成员变量
transient int size = 0;
transient Node<E> first;//头节点
transient Node<E> last;//尾节点
3)构造方法
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
//将c添加到链表的尾部
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {//index = size
//检查传入的集合大小是否合理
checkPositionIndex(index);
Object[] a = c.toArray();//集合转成数组
int numNew = a.length;//获取数组长度
if (numNew == 0)//如果长度是0,没有元素,直接返回
return false;
Node<E> pred, succ;//声明两个结点,前驱结点pred 、 后继结点succ
if (index == size) {//这里true,index表示在哪里开始添加,如果添加下标和链表大小相同,则就是在末尾添加
succ = null;//后继节点为空
pred = last;//前驱节点指向链表中的最后一个结点
} else {
succ = node(index);//获取到index位置的结点,succ指向此节点,也就是新建结点的后继结点指向index位置的结点
pred = succ.prev;//新建结点的前驱结点指向index位置结点的原来的前一个结点结点
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);//利用上面的前驱和后继结点创建一个结点,添加到链表
if (pred == null)//前驱结点是null,链表中没结点
first = newNode;//则初始化头节点
else
pred.next = newNode;//让pred的后继结点指向新添加的节点,也就是index位置原先的前一个结点的后继结点指向新节点,大白话就是在index位置和index-1位置直接新添加一个结点
pred = newNode;//然后让pred节点指向新添加的节点
}
if (succ == null) {//如果后继结点是空,初始化尾节点
last = pred;
} else {
pred.next = succ;//pred的下一个节点指向succ
succ.prev = pred;//succ的上一个节点指向pred
}
size += numNew;//链表中元素个数
modCount++;//链表改变标记+1
return true;
}
//获取到index处的结点
Node<E> node(int index) {
if (index < (size >> 1)) {//如果结点所在的位置在链表的前半段,则从前往后遍历
//一直将指针指到index处,获取到结点
Node<E> x = first;
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;
}
}
4)添加单个元素方法
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++;
}
添加结点时,只需要创建一个结点,然后链起来即可,所以增删效率高。
5)获取元素的方法
//获取到index处的结点
Node<E> node(int index) {
if (index < (size >> 1)) {//如果结点所在的位置在链表的前半段,则从前往后遍历
//一直将指针指到index处,获取到结点
Node<E> x = first;
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;
}
}
获取元素时,需要挨个遍历,所以查询效率低。
3、遍历LinkedList
1)for循环
LinkedList<String> list = new LinkedList<>();
list.add("1111");
list.add("2222");
list.add("3333");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
2)迭代器
LinkedList<String> list = new LinkedList<>();
list.add("1111");
list.add("2222");
list.add("3333");
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
3)增强for
LinkedList<String> list = new LinkedList<>();
list.add("1111");
list.add("2222");
list.add("3333");
for (String string : list) {
System.out.println(string);
}