private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
public LinkedList(Collection<? extends E> c) {
this();addAll(c);
}
这个构造方法传入一个Collection参数,且泛型为类的元素泛型的子类。然后调用无参构造方法,然后调用下面的addAll方法。
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
这个方法直接调用并返回下面的addAll方法并将上面的Collection参数和size成员变量一同传入,其中size作为下标的实参。
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
首先是判断传入的下标值是否越界,确保要添加的所有元素在不越界的情况下添加。
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
然后将Collection参数转换成数组,并且获取数组长度numNew,如果数组长度为空,也就是传入了个空集合,那么直接返回false。
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
定义两个节点,代表之前之后两个节点。
如果index和size相等也就是在链表结尾添加,那么succ节点也就是下一个节点就为空,pred节点也就是上一个节点为链表最后一个节点。pred就是predecessor也就是前任,succ就是successor就是继任。
如果index和size不等,也就是不在链表结尾添加,下一个元素就是index所属的元素,上一个元素就是index所属的上一个元素,说白了就是把新的链表插在index那里。
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;
}
然后遍历Collection参数形成的数组。
首先将Object数组的每个元素向下强转成泛型类型。然后创建新节点newNode,新节点的上一个节点为pred也就是插入位置的之前节点,新节点的后续结点为空。
如果pred为空,说明之前没有节点,那么first节点首节点就是新节点。否则将pred的下一个节点指向新节点。
然后将新节点作为上一个节点迎接下一次遍历。
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
遍历完成后,如果succ为空,也就是插入一串节点后,链表到了末尾,最后一个节点last节点就是pred,也就是刚最后遍历的节点。否则刚遍历的最后一个节点的下个节点就是succ,succ的上一个节点指向刚遍历的最后一个节点。
size += numNew;
modCount++;
return true;
}
最后链表长度相应增加,modCount自增代表改动次数加一,返回true