源码分析(5)-ArrayList、Vector和LinkedList(JDK1.8)

一、概述

1、线程安全:ArrayList和LinkedList非线程安全的、Vector线程安全的,synchronized同步锁机制

2、底层数据结构:ArrayList和Vector底层数据结构是数组;LinkedList双向链表。

3、时间复杂度是否受插入和删除元素位置影响:ArrayList和Vector受影响,add(E e)方法时间复杂度O(1)和add(int index, E element)方法时间复杂度O(n-index);LinkedList受影响,add(E e)方法时间复杂度O(1)和add(int index, E element)方法时间复杂度O(n)。

4、是否支持随机访问:ArrayList和Vector支持随机访问,因为实现了java.util.RandomAccess接口;LinkedList不支持。

5、内存空间占用:ArrayList和Vector空间浪费主要体现在在list列表的结尾会预留一定的容量空间;LinkedList空间花费则体现在每一个元素都需要消耗更多的空间(因为要存放前向元素和后向以及数据)。

6、是否支持克隆:ArrayList、Vector和LinkedList都实现java.lang.Cloneable接口,实现clone方法。

7、序列化:ArrayList、Vector和LinkedList都实现java.io.Serializable接口。

二、集合UML类图 

ArrayList和Vector继承和实现相同,LinkedList实现java.util.Deque<E>接口和继承java.util.AbstractSequentialList<E>抽象类。

  

三、ArrayList源码分析

 1、构造方法

 1 //无参构造方法
 2 public ArrayList() {
 3         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 4     }
 5 //指定初始容量的,构造方法
 6     public ArrayList(int initialCapacity) {
 7         if (initialCapacity > 0) {
 8             this.elementData = new Object[initialCapacity];
 9         } else if (initialCapacity == 0) {
10             this.elementData = EMPTY_ELEMENTDATA;//指定为默认空数组
11         } else {
12             throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
14         }
15     }
16 //指定初始集合对象,构造方法
17     public ArrayList(Collection<? extends E> c) {
18         elementData = c.toArray();//转化成数组
19         if ((size = elementData.length) != 0) {
20             // c.toArray might (incorrectly) not return Object[] (see 6260652)
21             if (elementData.getClass() != Object[].class)
22                 elementData = Arrays.copyOf(elementData, size, Object[].class);//复制数组到
23         } else {
24             // replace with empty array.
25             this.elementData = EMPTY_ELEMENTDATA;
26         }
27     }

 2、重要成员变量

//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认容量10的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//
数组,存储数据 transient Object[] elementData; //数组长度 private int size;
//最大的数组容量(长度)
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//数组结构变更次数
protected transient int modCount = 0; //该属性在父类java.util.AbstractList<E>中

3、插入

//添加元素    
public boolean add(E e) {
        ensureCapacityInternal(size + 1);//确认容量足够
        elementData[size++] = e;
        return true;
}
//
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//计算容量    
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);//初始化容量10,比较初始容量与最小容量,返回两者之间最大的那个的值
        }
        return minCapacity;
    }
// 确保容量
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//数组结构性修改次数+1
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//如果需要的最小容量大于当前数组长度,进行扩容
            grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);扩容1.5if (newCapacity - minCapacity < 0)//如果扩容后,扩容容量小于最小所需容量,扩容容量直接赋值最小所需容量
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);//设置最大容量
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);//复制数组
}
//指定位置添加数组    
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++;
}

4、删除

//删除元素
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);数组复制,index位置以后的元素前移1个位置
        elementData[--size] = null; // clear to let GC do its work
        return oldValue;
}

扩展:

 System.arraycopy()和Arrays.copyOf()方法:

//本地方法
public
static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
 1 //复制数组生成新的长度的数组
 2 public static <T> T[] copyOf(T[] original, int newLength) {
 3         return (T[]) copyOf(original, newLength, original.getClass());
 4     }
 5 //
 6     public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
 7         @SuppressWarnings("unchecked")
 8         T[] copy = ((Object)newType == (Object)Object[].class)
 9             ? (T[]) new Object[newLength]
10             : (T[]) Array.newInstance(newType.getComponentType(), newLength);
11         System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
13         return copy;
14     }

1、arraycopy()需要目标数组,将原数组拷贝到你自己定义的数组里,而且可以选择拷贝的起点和长度以及放入新数组中的位置。

2、copyOf()是系统自动在内部新建一个数组,并返回该数组。

四、Vector源码分析

成员方法和ArrayList相似,不同之处在于方法都是synchronized同步锁修饰。

1、构造方法 

//无参构造方法,初始容量10
    public Vector() {
        this(10);
    }
//指定初始容量构造方法
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
//指定初始容量和容量增长,构造方法
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
//指定集合的构造方法
    public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

2、重要成员变量

//数组,存储数据和ArrayList相同
protected Object[] elementData;
//数组长度,等同于ArrayList的size
protected int elementCount;
//扩容量
protected int capacityIncrement;

3、插入

//添加元素
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);//确保容量
        elementData[elementCount++] = e;//尾部添加元素
        return true;
    }
//
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);//扩容
    }
//
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);//如果容量增长大于0,容量增加capacityIncrement;如果不大于0,扩容2倍
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);//复制数组
    }

五、LinkedList源码分析

LinkedList是一个实现了List接口和Deque接口的双端链表。 LinkedList底层的链表结构使它支持高效的插入和删除操作,另外它实现了Deque接口,使得LinkedList类也具有队列的特性; LinkedList不是线程安全的,如果想使LinkedList变成线程安全的,可以调用静态类Collections类中的synchronizedList方法:

List list=Collections.synchronizedList(new LinkedList(...));

1、构造方法

//
public LinkedList() {}
//
public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

2、重要成员变量 

//双向链表节点长度
transient int size = 0;
//头结点
transient Node<E> first;
//尾结点
transient Node<E> last;

3、数据结构

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

4、插入

  //插入到头部  
    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);
        first = newNode;
        if (f == null)//头结点为空
            last = newNode;
        else
            f.prev = newNode;//原头结点的前一个节点指向新节点
        size++;
        modCount++;
    }
//尾部添加节点
    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++;
    }
 //插入节点默认在尾部添加   
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
//指定位置添加节点
    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++;
    }
//
    Node<E> node(int index) {
        // assert isElementIndex(index);

        if (index < (size >> 1)) {//插入位置小于0.5*size,正向遍历
            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;
        }
    }

4、删除

//删除指定位置元素
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));//遍历查询index位置元素
    }
//
    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;
    }

其他方法不再讲解。

原文地址:https://www.cnblogs.com/wangymd/p/12930627.html