//遍历数组
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
//修改长度
size += numNew;
//修改计数器
modCount++;
return true;
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
上面的这一大堆逻辑实际上就是将参数集合中的所有元素作为初始化 LinkedList 的元素。
常用的方法
=====
一、添加元素的方法
---------
在 LinkedList 中,提供了 6 个用于添加元素的方法。
**1\. boolean add(E e) —— 向集合的末尾添加元素,结果返回布尔值,表示操作是否成功。**
public boolean add(E e) {
//调用了下面的方法
linkLast(e);
return true;
}
void linkLast(E e) {
//获取双向链表的最后一个元素
final Node<E> l = last;
//新建一个节点,这个节点的上一个节点的值为原来的链表最后的一个节点的的值;下一个节点为null
final Node<E> newNode = new Node<>(l, e, null);
//记录最新的最后一个节点
last = newNode;
//如果原链表的最后一个节点为null,则新创建的节点就是第一个节点;否则,就将原来最后一个节点的下一个节点的引用改为新创建的节点
if (l == null)
first = newNode;
else
l.next = newNode;
//改变长度与计数器
size++;
modCount++;
}
**2\. void add(int index,E element) —— 在链表的某个位置插入元素**
public void add(int index, E element) {
//检查索引是否越界
checkPositionIndex(index);
//如果要插入的位置是链表的末尾,则调用上面分析过的方法;否则调用linkBefore,具体看后面分析
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
void linkBefore(E e, Node succ) {//参数element是待添加的元素;succ是插入位置的节点
//获取待插入位置节点的上一个节点的引用
final Node<E> pred = succ.prev;
//创建一个新的节点
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
//如果插入的位置是链表的起始端,则需要将该节点赋值给first记录
if (pred == null)
first = newNode;
else
//否则,将原来这个位置上的节点的下一个节点的引用修改为该节点引用
pred.next = newNode;
//修改长度与计数器
size++;
modCount++;
}
**3\. boolean addAll(Collection<? extend E> c) —— 将参数集合中的所有元素添加到链表末尾,结果返回布尔值,表示操作是否成功。**
public boolean addAll(Collection<? extends E> c) {
//调用了下面的重载方法
return addAll(size, c);
}
//这个也是第四个方法,将参数集合中的所有元素添加到指定的位置。
public boolean addAll(int index, Collection<? extends E> c) {
//老规矩,先检查下标是否越界
checkPositionIndex(index);
//熟悉的配方,将集合转换为数组
Object[] a = c.toArray();
//获取转换后数组的长度
int numNew = a.length;
//如果数组长度为0,则直接返回false
if (numNew == 0)
return false;
//声明两个节点
Node<E> pred, succ;
//如果待插入位置就是链表的末尾,则将succ置为null;pred就是最后一个节点
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
//细看这个方法其实跟带参构造器是相似的,上面已经分析过了,这里就省略了。
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
//修改长度和计数器
size += numNew;
modCount++;
return true;
}
**5\. void addFirst(E e) —— 在链表的起始端插入元素。**
public void addFirst(E e) {
//调用另外一个方法
linkFirst(e);
}
private void linkFirst(E e) {
//获取链表原来第一个节点
final Node<E> f = first;
//新建一个节点(这个就是链表未来的第一个节点)
final Node<E> newNode = new Node<>(null, e, f);
//将新建的这个节点赋值给fist(更新记录)
first = newNode;
//如果当前的链表是空的,则这个也是最后一个节点
if (f == null)
last = newNode;
//否则,将原来的第一个节点变成第二个节点
else
f.prev = newNode;
//修改长度和计数器
size++;
modCount++;
}
**6\. void addLast(E e) —— 在链表的末尾添加元素。**
public void addLast(E e) {
//调用另外一个方法
linkLast(e);
}
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++;
}
二、获取与修改元素的方法
------------
**1\. E get(int i) —— 获取某个位置上的元素**
public E get(int index) {
//检测参数是否合法(是否越界)
checkElementIndex(index);
//返回这个节点的item属性,node(index)返回的是index位置的这个节点
return node(index).item;
}