我在阅读源码的过程中很多时候是没有头绪的。所以为了避免大家也遇到这种状况,源码不求全求大,做到“透过实践看源码”,分块分层。
- 首先创建集合对象,添加数据
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("first");
list.add("second");
}
源码分析:
相关属性:
//链表元素数量
transient int size = 0;
/**
* 链表首节点
*/
transient Node<E> first;
/**
* 链表尾节点
*/
transient Node<E> last;
/**
* 构造函数
*/
public LinkedList() {
}
以上并没有进行什么初始化操作;
- 添加数据
/**
* 添加数据元素
*/
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 将元素e添加至链表末尾,
* 双向的,类似于:first--->A---->B---->...--->last
* <-- <--- <--- ...<--
*/
void linkLast(E e) {
//第一次添加数据,因为last并没有实例化,所以l不是指向last的引用,l=null
final Node<E> l = last;
//根据添加的元素创建一个节点,将last节点作为prev节点,next节点设置为空,随后设置
final Node<E> newNode = new Node<>(l, e, null);
//将新构建的节点作为last节点,保证每次添加都添加至末尾
last = newNode;
//第一次添加,将first指向newNode节点(新构建的)
if (l == null)
first = newNode;
else
l.next = newNode;//以后每次都将最后一个节点的next只想新节点
size++;//元素数递增
modCount++;
}
- 添加数据还可以使用压入push
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("first");
list.add("second");
list.push("zero");
}
源码分析:
/**
* 压入
* 在首节点处增加数据
*/
public void push(E e) {
addFirst(e);
}
/**
* 在首节点添加数据
*/
public void addFirst(E e) {
linkFirst(e);
}
/**
* 作为首节点链接入集合
*/
private void linkFirst(E e) {
final Node<E> f = first;
//构造新节点,指定next节点是first
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
//第一次添加数据,f==null;first和last均指向新节点
if (f == null)
last = newNode;
else
f.prev = newNode;//成功构建双向节点,加入链表
size++;
modCount++;
}
- 获取链表元素值
public static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("first");
list.add("second");
list.push("zero");
System.out.println(list.getFirst());
System.out.println(list.getLast());
}
运行结果:
zero
second
源码分析:
/**
* 返回链表第一个元素值
*/
public E getFirst() {
final Node<E> f = first;
//未添加数据,f==null,抛出异常
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 static void main(String[] args) {
LinkedList<String> list=new LinkedList<String>();
list.add("first");
list.add("second");
list.push("zero");
list.remove("zero");
System.out.println(list.getFirst());
System.out.println(list.getLast());
}
运行结果:
first
second
源码分析:
/**
*根据值进行删除
*/
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;
}
/**
* 删除节点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;
//如果删除的是第一个节点,prev=null
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;
}