JAVA集合面面观

List的常用实现:vector,ArrayList,linkedList。

总体关系如下(java8):

vector和arraylist

两者底层都是采用数组的形式。但是有些许不同

    //  ArrayList
    transient Object[] elementData; // non-private to simplify nested class access

// vector
protected Object[] elementData;
  • 在序列化的时候,arraylist将会调用writeObject和readObject方法来序列化。所以比vector在序列化上更安全。
  • 其次,vector的主要元素操作方法都是synchronize修饰的来保证线程安全。(现在基本抛弃vector。代替Collections.synchronizeList的方法来构造线程安全)
  • vector的构造函数允许扩展的步长。
arraylist和linkedlist

arraylist底层是数组实现
linkedlist是链式的线性表,也是双向链表,因为从上图可以看到它还实现了Deque,可以用做双端队列,或者栈使用。

arraylist是数组实现,所以对于修改List的操作,会进行整体的搬家。

public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

可以看出,对于修改数据的操作,会非常重。但是相对于get将非常快。直接操作下标获取。

public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
E elementData(int index) {
        return (E) elementData[index];
    }

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

看实现可以知道。当修改元素的时候,只需要修改节点对应的前节点和后节点就能完成插入。

public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }
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++;
    }

然后看get, 需要从头或者从末开始遍历。

public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
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;
        }
    }

另外linkedlist实现了Deque。提供的几个方法,所以可以作为队列使用。

// 待续

猜你喜欢

转载自www.cnblogs.com/ywd979/p/9715294.html