容器-LinkedList指定位置添加元素的源码分析(九)
-
LinkedList指定索引位置添加元素
-
public static void main(String[] args) { List<String> list= new LinkedList<>(); //添加元素 list.add("a"); list.add("b"); list.add("c"); list.add("a"); list.add(5,"aaaa");//如果索引为5,则IndexOutOfBoundsException索引下标越界异常,因为现在的链表之有个元素,索引最多为3,如果你索引为4还是可以添加到索引为3后面的,但是索引5就不行了, 你跳过了4,就会出现索引下标越界异常。
-
-
用Ctrl+鼠标左键进入add源码,
void add(int index, E element);
-
在用Ctrl+Alt选择add方法的LinkedList接口实现类
/** * Inserts the specified element at the specified position in this list. * Shifts the element currently at that position (if any) and any * subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { checkPositionIndex(index);//校验当前索引位置是否合法 if (index == size) linkLast(element); else linkBefore(element, node(index)); }
-
然后我们看 checkPositionIndex(index);
private void checkPositionIndex(int index) { if (!isPositionIndex(index))//isPositionIndex的方法是有返回值的,返回的是布尔类型 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); //如果isPositionIndex返回的是true,再取非,则不执行if条件语句 //如果isPositionIndex返回的是false,再取非,则执行if条件语句,抛出异常 }
-
继续看isPositionIndex的方法实现
/** * Tells if the argument is the index of a valid position for an * iterator or an add operation. */ private boolean isPositionIndex(int index) { return index >= 0 && index <= size; //校验索引的合法性,就是索引大于等于0,还有索引小于等于元素的个数 }
-
我们返回去看最初的add方法,现在校验checkPositionIndex(index)已经合格,继续下面的语句
public void add(int index, E element) { checkPositionIndex(index);//校验当前索引位置是否合法 if (index == size)//如果索引等于元素的个数,则在元素的后面添加元素 linkLast(element); else//当索引小于元素的个数时,调用linkBefore()方法,把element穿进去了,通过node()方法,把index传进去了,node()方法是有返回值的,最终他要返回给linkBefore()方法取执行 linkBefore(element, node(index)); }
-
来看下node()的方法(重要理解)
/** * Returns the (non-null) Node at the specified element index. */ Node<E> node(int index) { // node是有返回值的,返回一个node的对象 // assert isElementIndex(index); //这是一个折半查找。 if (index < (size >> 1)) { 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; } }
-
node方法的具体分析
-
-
然后我们回去看 linkBefore(element, node(index));
/** * Inserts element e before non-null Node succ. */ void linkBefore(E e, Node<E> succ) { // assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; }
-
分析 linkBefore方法的原理
- 所以说双向链表比数组增加删除元素效率高的原因,而为什么查询效率低呢,因为它要从头开始查到尾。