LinkedList这个集合想必大家都有使用过,它是java单列集合Collection的一个实现。
LinkedList有以下几个特点:
- 底层数据结构是双向链表
- 内部不保存下标
- 线程不安全
LinkedList的使用十分简单,这里不再给出,重点讲下LinkedList的源码和底层实现。
首先看一下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;
}
}
Node是LinkedList的静态内部类,主要有item,next,prev3个属性。
- item 用于存储值,就是我们往集合中放的数据
- next 下一个节点的引用
- prev 前一个节点的引用
从属性上也可以看出LinkedList底层是一个双向链表。
再看一下LinkedList的其他属性:
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
- size 保存集合的长度
- first 集合中的第一个节点
- last 集合中的最后一个节点
然后就是LinkedList的主要方法
- void linkFirst(E e) 从集合前面添加元素
- void linkLast(E e) 从集合后面添加元素
- Node node(int index) 获取指定位置节点
- E unlink(Node x) 删除一个节点
- E set(int index, E element) 修改指定下标的元素
下面会一一讲解
void linkFirst(E e) 从集合前面添加元素
private void linkFirst(E e) {
//取出首节点
final Node<E> f = first;
//创建一个节点, 元素为e, prev为null, next为首节点
final Node<E> newNode = new Node<>(null, e, f);
//首节点变为新创建节点
first = newNode;
//如果原有首节点不存在, 证明集合中没有节点,新添加的为第一个节点,所以既是首节点又是尾节点
//如果原有首节点存在, 那就把原有首节点的prev变为新创建的节点
if (f == null)
last = newNode;
else
f.prev = newNode;
//集合长度加1
size++;
modCount++;
}
void linkLast(E e) 从集合后面添加元素
void linkLast(E e) {
//取出尾节点
final Node<E> l = last;
//创建一个新节点,元素为e, prev为尾节点
final Node<E> newNode = new Node<>(l, e, null);
//尾节点变为新建节点
last = newNode;
//原尾节点为空, 证明集合中没有节点,新添加的为第一个节点,所以既是首节点又是尾节点
//原尾节点不为空, 原尾节点的next变为新建节点
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
Node node(int index) 获取指定位置节点
Node<E> node(int index) {
//如果index小于链表长度的一半,从首节点开始查找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//index大于等于链表长度的一半,从尾节点开始查找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
//从这里也可以看出LinkedList查询效率较低,只能遍历链表
}
E unlink(Node x) 删除一个节点
E unlink(Node<E> x) {
//取出节点元素,用于返回
final E element = x.item;
//取出该节点的next,prev
final Node<E> next = x.next;
final Node<E> prev = x.prev;
//prev为空,证明该节点为首节点,移除该节点后next变为首节点
if (prev == null) {
first = next;
} else {
//prev不为空,prev和next相连接
prev.next = next;
x.prev = null;
}
next为空,证明该节点为尾节点,移除该节点后prev变为尾节点
if (next == null) {
last = prev;
} else {
//next不为空,next和prev相连接
next.prev = prev;
x.next = null;
}
//元素置为null
x.item = null;
//长度-1
size--;
modCount++;
return element;
}
E set(int index, E element) 修改指定下标的元素
此方法非常简单,有兴趣的可阅读下源码
public E set(int index, E element) {
// 检查下标是否合法(index >= 0 && index < size )
checkElementIndex(index);
// 取出该下标的节点
Node<E> x = node(index);
// 取出旧值
E oldVal = x.item;
// 设置新值
x.item = element;
// 返回旧值
return oldVal;
}
以上方法在什么时候被调用?
linkFirst: 在我们调用add,addFirst时
linkLast: 在我们调用addLast时
node: 在我们调用get时
unlink: 在我们调用remove方法时
set: 本身就是public方法,由我们调用
版权声明:本文为weixin_42588659原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。