LinkedList

88 阅读2分钟

存对象

从初始化对象开始

public LinkedList() {
}

构造方法里面啥都没有,从add开始

public boolean add(E e) {
    linkLast(e);
    return true;
}

调用到linkLast(),因为add是添加,所以这个调用的方法也叫last,毕竟是按平常的道理,添加是一条一条依次叠加,新加的在前一次的基础上叠加,看看方法

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++;
}
//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;
    }
}
  • last是当前的一个成员变量,但是咱们从构造方法到add,last没有机会做任何初始化以及赋值操作,所以 last为null,所以newNode这个变量除了item,其他两个都为null。

  • 再接下来是给last赋值,因为每次add的话,如果不是指定index,那么这个add的就是最后一个,所以把当前的值给last

  • 因为第一次last会为null,所以第一次给first变量赋值,也为newNode,然后size++,一个添加就完成了。

  • 第二次添加的时候,last有值了,会走l.next = newNode,这样就把上一个的Node的next变量指向了当前你添加的这个Node

取对象

咱们从get方法开始

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}

首先是对索引进行校验,看它有没有超出size,超出就抛出异常,否则就是取数据,调用node()方法

Node<E> node(int index) {
    // 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;
    }
}

先对index检查,看它位于整个List的前端还是后端,前端就first开始取,后端就从last开始取,从头到尾遍历一遍才取到,所以说这个链表在取固定索引位置得数据消耗性能,得从头到尾的变量一遍才取到想要的数据,能不耗性能吗,添加的话相对来说就方便多了,没有像ArrayList那样,扩容,复制,这些操作

删对象

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;
}

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;

    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;
}
  • 首先是分两种情况,第一种传的null,走上面的循环,从first开始,直到最后一个值,假如碰到Node里面item为null的话,就把Node里面的指针更新。
  • 如果碰到prev为null的话,就说明当前是第一个对象,又因为当前的item为null,所以给first赋值为next。
  • prev不为null的话,说明不是第一个,当前的item为null,所以要把上一个的next指向改为当前的next,然后把当前的上一个指向置为空。