浅谈Java集合框架——ArrayList、LinkedList、Vector

数组和集合

  1. 数组:存储对象的一种容器(可以存储基本类型数据),数组最大的缺点就是长度固定,一不建议使用。
  2. 集合:类集实际上就属于动态对象数组(只能存储对象,且对象的类型可以不同),与数组相比最大的好处就是长度可以改变。

下面为Java的集合框架图
菜鸟教程
这里写图片描述

从面的集合框架图可以看出,所有的集合类都实现了Iterator接口,且Java集合主要包含两种容器:

Iterator: 此接口用于遍历集合中的元素。

主要有如下方法:

hasNext():是否存在下一个元素
next():返回下一个元素
remove():删除当前元素

集合(Collection): 存储一个元素的集合。此接口是集合类的根接口,Java中没有提供该接口的直接实现类,但是有两个接口
(List和Set)继承了该Collection接口

图(Map): 存储键值对映射。同样是属于java.util包下的另外一个接口,和Collection是相互独立的、没有关系,

Collection接口提供的方法

主要方法详解:
add():将指定的对象存储到容器中
addAll():将指定集合中的所有元素添加到此集合 
clear():从此集合中删除所有元素
remove():将指定的对象在集合中删除
removeAll():将指定的集合中的元素删除
isEmpty():判断集合是否为空
contains():判断集合中是否包含指定对象
containsAll():判断集合中是否包含指定集合
equals():判断两个对象是否相等
size():返回集合容器的大小
toArray():集合转化为数组
List集合
List接口对Collection接口的方法进行了扩充:
get():根据索引取得保存数据
set():修改数据
并且List集合仍然为接口,不可以进行实例化,要想取得实例化需要有子类,

List的常用子类:ArrayList、LinkedList、Vector

List:有序的Collection、允许数据重复
    ArrayList:底层是数组实现。因为是数组实现,所以在进行增加和删除元素时会涉及到整个数组的扩容以及
               拷贝元素,所以速度相对较慢;而数组可以直接使用索引进行查找,速度相对较快。
    LinkedList:底层是双链表实现。因为是链表实现,增加和删除元素时,只需要改变节点的指向,所以效率较高;
               而进行查元素时,需要一个个进行遍历,速度相对较慢。
    Vector:底层是数组实现。和ArrayList原理相同,但是是线程安全的,效率比其低。

适用场景分析:
List集合使用与顺序存储,允许元素重复出现,List接口中常用的实现类是ArrayList和LinkedList;若查询较多的话使用
ArrayList,插入和删除元素较多的haul使用LinkedList,若对线程安全有要求的话就是用Vector。
ArrayList
ArrayList就是传说中的动态数组,即是Array的复杂版本,提供有如下的好处:
(1)动态增加和减少元素
(2)实现了Collection和List接口

(3)灵活的设置数组的大小

  • ArrayList的构造器:
//默认构造器,构造一个空列表,初始容量为10
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
//用指初始容量来构造空列表
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
//用一个Collection对象来构造,并将该集合的元素添加到ArrayList
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

- ArrayList的同步

在Java集合工具类Collections中,提供了一个Collections.synchonizedList方法,可以传入一个List对象,返回一个
SynchronizedList。SynchronizedList只是对List对象的封装,对List的每个操作都添加可synchonized修饰,基本上与Vector一致。

- 部分源码剖析

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//序列版本号
    private static final long serialVersionUID = 8683452581122892189L;
//默认初始容量
    private static final int DEFAULT_CAPACITY = 10;
//用于空实例的共享空数组实例
    private static final Object[] EMPTY_ELEMENTDATA = {};
//用于默认大小空实例的共享空数组实例
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数组缓冲区中存储ArrayList元素的数组缓冲区。ArrayList的容量是这个数组缓冲区的长度
    transient Object[] elementData; // non-private to simplify nested class access
//ArrayList的大小(它包含的元素的数量)。
    private int size;

//此处省去构造函数(在前期有说明)

//将当前容量值设为实际元素的个数()
//modCount在AbstractList中定义,表示列表在结构上被修改的次数
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA
              : Arrays.copyOf(elementData, size);
        }
    }
//确定ArrayList的容量
//当容量不足以容纳当前全部元素,设置新的容量=(原始容量*3)/2
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private void ensureExplicitCapacity(int minCapacity) {
    //将修改统计数+1
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
//要分配集合的最大大小
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

//定义扩容方式。确保至少能保持
由最小容量参数指定的元素个数。
    private void grow(int minCapacity) {
        // overflow-conscious code
        //旧容量 = 数组的长度
        int oldCapacity = elementData.length;
        //新的容量为旧容量+旧容量的一般(扩容方式是每次扩充原始容量的一般,即是旧容量的1.5倍)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (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);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

//返回列表中的元素个数
    public int size() {
        return size;
    }

//判断集合是否为空。如果这个列表不包含任何元素,那么返回true
    public boolean isEmpty() {
        return size == 0;
    }

//判断集合中是否包含指定元素。如果这个列表包含指定的元素,则返回true。
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
//返回指定元素的第一次出现的索引,若不存在此元素返回-1
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
//返回指定元素的第一次出现的索引,若不存在此元素返回-1
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
//克隆。返回这个ArrayList实例的一个浅副本。
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
//将转化为数组,按照适当的顺序(从第一个元素到最后一个元素)返回包含列表中所有元素的数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
//返回指定位置的元素
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
//用指定元素替换集合中指定位置的元素
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
//在集合末尾添加指定的元素
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
//在指定的位置添加指定元素
    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++;
    }
//删除集合中指定位置的元素
    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 boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
//跳过边界检查的私有移除方法,
    private void fastRemove(int index) {
        modCount++;
        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
    }
//删除集合中所有的元素
    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }
//将指定集合的所有元素添加至原来集合的末尾
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }
//将指定集合的所有元素添加至原来集合的指定位置
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }
//删除集合中指定索引之间的元素
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }
//检查指定的索引是否在范围内
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    /**
     * A version of rangeCheck used by add and addAll.
     */
    private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
//
    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }
//从集合中删除指定集合中所包含的所有元素
    public boolean removeAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, false);
    }
//只保留指定1集合中锁包含的元素
    public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }
// java.io.Serializable的写入函数
// 将ArrayList的“容量,所有的元素值”都写入到输出流中
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();
        //写入“数组的容量”
        s.writeInt(size);
        //写入“数组中的每一个元素”
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }
// java.io.Serializable的读取函数:根据写入方式读出
// 先将ArrayList的“容量”读出,然后将“所有的元素值”读出
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();
        //从输入流中读取ArrayList的“容量”
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            //从输入流中将“所有的元素值”读出
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }
//返回集合自身的迭代器。从集合中的指定位置开始。
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }   
//以指定的顺序返回集合元素
    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        Itr() {}
}

- ArrayList的扩容机制

此扩容机制应该是对ArrayList效率影响的较大的因素,因为每当执行Add、AddRange、Insert、InsertRange等元素添加操作时,每次都会检查集合内部容量
是否足够,每当添加一个元素都会以当前容量的1.5倍来重新构建一个新的数组,将旧的集合中的元素拷贝至新的集合中,然后删除旧的集合。这个临界点的扩容
机制相对来说是比较影响效率的。

- TrimSize方法

此方法用于将ArrayList固定到实际元素的大小,当动态数组元素确定不再进行添加元素操作时,可以调用此方法来释放空余的内存。

- 内部Object类型的影响

对于一般的·引用类型而言,影响不是很大。但是对于值数据来说,向ArrayList中添加修改元素都会引起拆箱和装箱的操作,频繁的操作可能会影响效率。
(但多数的应用都是使用值类型数据,所以要使用就要承担一部分的效率损失,但是不会很大。)

- 效率损失

若我们频繁的使用indexOf、Contains等方法,会引起效率损失。
首先我们应该明确,ArrayList是动态数组,不支持通过key和value来进行快速的访问,实则我们调用的IndexOf、Contains方法都是执行简单的循环来查找
元素,索引效率较慢,。若有此要求可以使用Hashtable和SortedList等键值对结合。

- ArrayList的优缺点

ArrayList实现了List接口,ArrayList的底层数据结构是数组。
数组结构的优点是:**方便对集合进行快速的随机访问** 若要经常根据索引位置访问集合对象使用ArrayList较好。
数组结构的缺点是:**向指定索引位置插入和删除速度较慢**若要经常性地插入和删除指定索引的对象,则效率较低,因为当插入或删除时,会同时将索引
后的元素相应的向后或向前移动。如果在指定索引后有大量元素,则会严重影响效率。

LinkedList

LinkedList是继承自AbstractSequentialList的双向链表;可以被当做堆栈、队列、双端队列来进行处理。
LinkedList实现List接口,可以对其进行队列操作。
LinkedList实现Deque接口(JDK1.6),Deque支持在两端进行操作,即可以当作双端队列来使用。
LinkedList实现了Cloneable接口,即覆盖了clone函数,可以对其进行克隆。
LinkedList实现了java.io.Serializable接口,表明了LinkedList支持序列化,可通过序列化来进行传输
LinkedList是非同步的。

- LinkedList的构造器

//构造一个空列表(默认构造函数)
  public LinkedList() {
    }
//创建一个LinkedList,包含Collection中的所有元素
 public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }

- AbstractSequentialList简介(LinkedList的父类)

AbstractSequentialList是LinkedList的父类,实现了get、set、add、remove等方法,这些方法都是随机访问List的;LinkedList是继承自其的双向链表,
同样也可以是使用上述方法来进行随机访问。

- LinkedList类的继承结构

这里写图片描述

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList本质是双向链表。继承自AbstractSequentialList接口,并且实现了Deque接口。
LinkedList有三个重要的成员变量:size(是双向链表中节点的个数),first(指向第一个节点的指针),last(指向最后一个节点的指针)

- LinkedList部分源码剖析

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    //LinkedList中元素的个数
    transient int size = 0;
    //指向第一个节点的指针
    transient Node<E> first;
    //指向最后一个节点的指针
    transient Node<E> last;

    //此处省去构造函数

    //创建新节点作为第一个元素
     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;
        //链表长度+1
        size++;
        modCount++;
    }
    //创建新节点作为尾节点
    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 E getFirst() {
        final Node<E> f = first;
        if (f == null)
            throw new NoSuchElementException();
        //做最初已经将新的元素作为表头first所以第一个元素就是first所包含的元素
        return f.item;
    }
    //返回链表中最后一个元素
    public E getLast() {
        final Node<E> l = last;
        if (l == null)
            throw new NoSuchElementException();
        //直接返回尾节点所含元素
        return l.item;
    }
    //清空双向链表
    public void clear() {
        //从表头开始向后遍历,对每个节点执行以下操作
        //先对当前节点进行保存
        //设置其内容为null
        //设置节点的下一个节点和前一个节点为null
        //设置后一个节点为“当前节点”
        for (Node<E> x = first; x != null; ) {
            Node<E> next = x.next;
            x.item = null;
            x.next = null;
            x.prev = null;
            x = next;
        }
        first = last = null;
        //并设置其大小为0
        size = 0;
        modCount++;
    }
    //返回指定位置对应节点的值
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
    //设置指定的节点对应值为指定值
    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }
    //在index之前插入节点的值为element
    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
        //进行在指定节点前插入
            linkBefore(element, node(index));
    }
    //删除指定位置的节点
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
    //获取双向链表中指定位置的节点
    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;
        }
    }
    //查找指定值所对应的索引,从头开始向尾部进行查找,若找不到返回-1
    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
    //查找指定值所对应的索引,从尾部开始向头部进行查找,若找不到返回-1
     public int lastIndexOf(Object o) {
        int index = size;
        if (o == null) {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (x.item == null)
                    return index;
            }
        } else {
            for (Node<E> x = last; x != null; x = x.prev) {
                index--;
                if (o.equals(x.item))
                    return index;
            }
        }
        return -1;
    }
    //返回第一个节点(如第一个节点为null,则返回null)
     public E peekFirst() {
        final Node<E> f = first;
        return (f == null) ? null : f.item;
     }
      //返回最后一个节点(如最后一个节点为null,则返回null)
     public E peekLast() {
        final Node<E> l = last;
        return (l == null) ? null : l.item;
    }
    //返回“指定位置到末尾的全部节点”对应的ListIterator对象(List迭代器)
     public ListIterator<E> listIterator(int index) {
        checkPositionIndex(index);
        return new ListItr(index);
    }

    //List迭代器
       private class ListItr implements ListIterator<E> {
       //上一个返回的节点
        private Node<E> lastReturned;
        //下一个节点
        private Node<E> next;
        //下一个节点对应的索引值
        private int nextIndex;
        //期望的改变计数器,用来实现fail-fast机制
        private int expectedModCount = modCount;

        //构造函数(从index开始进行迭代)
        ListItr(int index) {
            next = (index == size) ? null : node(index);
            nextIndex = index;
        }
        //是否存在下一个元素
        public boolean hasNext() {
            //通过元素的索引是否小于“双向链表的长度”来判断是否到达最后位置
            return nextIndex < size;
        }
        //获取下一个元素
        public E next() {
            checkForComodification();
            if (!hasNext())
                throw new NoSuchElementException();
            lastReturned = next;
            //next指向链表的下一个元素
            next = next.next;
            nextIndex++;
            return lastReturned.item;
        }
        //是否存在上一个元素
        public boolean hasPrevious() {
            return nextIndex > 0;
        }
        //获取上一个元素
        public E previous() {
            checkForComodification();
            if (!hasPrevious())
                throw new NoSuchElementException();
            //next指向链表的上一个元素
            lastReturned = next = (next == null) ? last : next.prev;
            nextIndex--;
            return lastReturned.item;
        }
        //获取下一个元素的索引
        public int nextIndex() {
            return nextIndex;
        }
        //获取上一个元素的索引
        public int previousIndex() {
            return nextIndex - 1;
        }
        //删除当前元素(删除双向链表中的当前节点)
        public void remove() {
            checkForComodification();
            if (lastReturned == null)
                throw new IllegalStateException();
            Node<E> lastNext = lastReturned.next;
            unlink(lastReturned);
            if (next == lastReturned)
                next = lastNext;
            else
                nextIndex--;
            lastReturned = null;
            expectedModCount++;
        }
        //设置当前节点为指定值
        public void set(E e) {
            if (lastReturned == null)
                throw new IllegalStateException();
            checkForComodification();
            lastReturned.item = e;
        }
        //将指定元素添加至当前节点的前面
        public void add(E e) {
            checkForComodification();
            lastReturned = null;
            if (next == null)
                linkLast(e);
            else
                linkBefore(e, next);
            nextIndex++;
            expectedModCount++;
        }
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            while (modCount == expectedModCount && nextIndex < size) {
                action.accept(next.item);
                lastReturned = next;
                next = next.next;
                nextIndex++;
            }
            checkForComodification();
        }
        //判断modCount和expectedModCount是否相等,来
        实现fail-fast机制
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}

- LinkedList总结

(1)LinkedList是通过双向链表实现的,包含一个重要的内部类Node。Node是双向链表节点所对应的数结构,包含当前节点
     的值,上一个节点,下一个节点。
(2)LinkedList不存在容量不足的问题。
(3)LinkedList的克隆函数是将全部元素克隆到一个新的LinkedList对象中
(4)LinkedList实现了Deque接口,在此接口中定义了双端队列两端访问元素的方式。

- LinkedList作为FIFO(先进先出)队列

等效方法:
队列方法    LinkedList方法
add()<------->addLast()
offer()<------->offLast()
remove()<------->removeFirst()
poll()<------->pollFirst()
element()<------->getFirst()
peek()<------->peekFirst()

- LinkedList作为LIFO(先进后出)的栈

栈方法       LinkedList方法
push()<------->addFirst()
pop()<------->removeFirst()
peek()<------->peekFirst()

- LinkedList集合的遍历方式

(1)通过迭代器遍历,即使用Iterator来进行遍历
for(Iterator iterator = list.iterator;iterator.hasNext();){
    iterator.next();
}
(2)通过随机访问遍历LinkedList
int size = list.size();
for(int i = 0; i < size;i++){
    list.get(i);
}

(3)通过pollFirst()遍历LinkedList
while(list.pollFirst()!=null);

(4)通过pollLast()遍历LinkedList
while(list.pollLast()!=null);

(5)通过removeFirst()遍历LinkedList
while(list.removeFirst()!=null);

(6)通过removeLast()遍历LinkedList
while(list.removeLast()!=null);
Vector
(1)Vector是动态数组实现的List,和ArrayList一样,存在自动扩容机制。
(2)Vector是在JDK1.0引入的,因为许多方法都加了同步语句,所以是线程安全的。
(3)Vector适用于进行快速查找和修改的场景,不适合用于随机的查找和删除操作。
(4)Vector初始化容量为10,扩容由初始化容量和capacityIncrement共同决定。
(5)Vector允许元素为null
(6)Vector不推荐使用,若不需要考虑线程安全的实现,则可用ArrayList来代替Vector。
  • Vector的继承结构
  • 这里写图片描述

- Vector构造器

Vector中提供四个构造函数
//两个整形参数的构造方法,
//initialCapacity为初始容量大小,
//capacityIncrement为扩容增加值,大于0则增加capacityIncrement,否则,翻倍
public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
//一个参数构造方法
//initialCapacity默认容量大小。当增加数据导致容量增加时,每次容量会增加一倍
public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
//默认构造方法
public Vector() {
        this(10);
    }
//创建一个包含collection的Vector
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);
    }

- Vectord的扩容

Vector在每次增加元素时,都要确保有足够的容量。当容量不足以容纳当前元素时,就先
看构造方法中传入的容量增长量参数CapacityIncrement是否为0.
(1)如果不为0,就设置新的容量为旧的容量加上容量增长量
(2)如果为0,就设置容量为旧容量的2倍
(3)如果设置后新容量还是不够,则直接新容量设置为传入的参数(即所需要的容量)
(4)而后同样用Arrays.copyof()方法将元素拷贝到新的数组
 public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }
     private void ensureCapacityHelper(int minCapacity) {
        // 需要进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    private void grow(int minCapacity) {
        // 旧容量 = 所含元素的长度
        int oldCapacity = elementData.length;
        //扩容大小 ? capacityIncrement 或 翻倍
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
Vector的扩容大小由当前元素个数oldCapacity = elementData.length和属性capacityIncrement共同决定:
(1)capacityIncrement<=0,则扩容大小为oldCapacity,即翻倍
(2)若capacityIncrement>0,则扩容大小为capacityIncrement的大小。
(3)Vector容量大小限制:
在JDK1.6之前扩容没有限制容量大小,但是在JDK1.8中限制了容量大小最大为Integer.MAX_VALU(2^31 - 1).

  • Vector部分源码剖析
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//保存Vector数据的数组
 protected Object[] elementData;
 //实际的数量
 protected int elementCount;
 //容量增长系数
 protected int capacityIncrement;
 //Vector的序列版本号
 private static final long serialVersionUID = -2767605614048989439L;
 //构造函数(默认容量为10)
 public Vector() {
        this(10);
    }
 //指定Vector容量大小的构造函数
 public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
 //指定Vector容量大小和“增长系数”的构造函数
 public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        // 新建一个数组,数组容量是initialCapacity
        this.elementData = new Object[initialCapacity];
        // 设置容量增长系数
        this.capacityIncrement = capacityIncrement;
    }
 //指定集合的Vector构造函数
 public Vector(Collection<? extends E> c) {
        // 获取“集合(c)”的数组,并将其赋值给elementData
        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);
    }
  // 将数组Vector的全部元素都拷贝到数组anArray中
 public synchronized void copyInto(Object[] anArray) {
        System.arraycopy(elementData, 0, anArray, 0, elementCount);
    } 
//将当前容量设为实际元素的个数
 public synchronized void trimToSize() {
        modCount++;
        int oldCapacity = elementData.length;
        if (elementCount < oldCapacity) {
            elementData = Arrays.copyOf(elementData, elementCount);
        }
    }
//确定Vector的容量
 public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            // 将Vector的改变统计数+1
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }
  // 确认“Vector容量”的帮助函数
 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;
        / 当Vector的容量不足以容纳当前的全部元素,增加容量大小。
        // 若 容量增量系数>0(即capacityIncrement>0),则将容量增大当capacityIncrement
        // 否则,将容量增大一倍。
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
  //设置新的容量大小为newSize
  public synchronized void setSize(int newSize) {
        modCount++;
        if (newSize > elementCount) {
        // 若 "newSize 大于 Vector容量",则调整Vector的大小
            ensureCapacityHelper(newSize);
        } else {
          // 若 "newSize 小于/等于 Vector容量",则将newSize位置开始的元素都设置为null
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }
    //返回Vector的总容量
    public synchronized int capacity() {
        return elementData.length;
    }
    // 返回“Vector的实际大小”,即Vector中元素个数
    public synchronized int size() {
        return elementCount;
    }
     // 判断Vector是否为空
     public synchronized boolean isEmpty() {
        return elementCount == 0;
    }
    // 返回“Vector中全部元素对应的Enumeration”
    public Enumeration<E> elements() {
       // 通过匿名类实现Enumeration
        return new Enumeration<E>() {
            int count = 0;
            // 是否存在下一个元素
            public boolean hasMoreElements() {
                return count < elementCount;
            }
            // 获取下一个元素
            public E nextElement() {
                synchronized (Vector.this) {
                    if (count < elementCount) {
                        return elementData(count++);
                    }
                }
                throw new NoSuchElementException("Vector Enumeration");
            }
        };
    }
     // 从index位置开始向后查找元素(o)。
    // 若找到,则返回元素的索引值;否则,返回-1
     public synchronized int indexOf(Object o, int index) {
        if (o == null) {
        // 若查找元素为null,则正向找出null元素,并返回它对应的序号
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
        // 若查找元素不为null,则正向找出该元素,并返回它对应的序号
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    // 从后向前查找元素(o)。开始位置是从前向后的第index个数;
    // 若找到,则返回元素的“索引值”;否则,返回-1。
 public synchronized int lastIndexOf(Object o, int index) {
        if (index >= elementCount)
            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

        if (o == null) {
        // 若查找元素为null,则反向找出该元素,并返回它对应的序号
            for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
        // 若查找元素不为null,则反向找出该元素,并返回它对应的序号
            for (int i = index; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //返回Vector中第index个元素,若index越界则抛异常
    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }
    //返回Vector中第一个元素,失败抛异常
    public synchronized E firstElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(0);
    }
    //返回Vector中最后一个元素,失败抛异常
    public synchronized E lastElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(elementCount - 1);
    }
    … …
    … …

- Vector的遍历方式

通过Iterator进行遍历
for(Iterator iter = vec.iterator(); iter.hasNext();)
    iter.next();

通过索引值遍历
Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}

Enumeration遍历
Integer value = null;
Enumeration enum = vector.elements();
while (enum.hasMoreElements()) {
    value = (Integer)enum.nextElement();
}

- Fail-Fast机制

Vector采用了快速失败机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,
而不是冒着在某一个不确定的时间发生任意不确定行为的风险。

Fail-Fast是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变操作时,有可能会产生Fail-Fast机制
但是也只是可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,
在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出
ConcurrentModificationException 异常,从而产生fail-fast机制。
ArrayList和Vector的比较
ArrayList和Vector最大的区别就是Vector是线程安全的,而ArrayList是线程不安全的,此外,还有以下区别。

  • ArrayList不可以设置扩展的容量,默认是1.5倍
  • Vector可以设置扩展的容量,如果没有设置,默认2倍
  • ArrayList无参构造方法中初始容量为0(第一次调用add()方法会更新到10)
  • Vector的无参构造方法中初始容量是10
  • ArrayList是线程不安全的
  • Vector是线程安全的
Collections.syschronizedList和Vector的比较

  • Vector是JDK1.0开始使用的,而集合框架爱是从JDK1.2开始加入的。
  • SyschronzedList和Vector的最主要区别
    (1)SyschronzedList有很好的扩展性和兼容功能,它可以将所有的List子类转化为线程安全的类
    (2)使用SyschronzedList时,若要进行遍历则需要手动进行同步处理
    (3)SyschronzedList可以指定锁定的对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的ArrayListLinkedListVector是三种常见的集合类,它们都实现了List接口,但在实现和使用上有一些区别。 1. 实现方式: - ArrayList是基于数组实现的动态数组,可以动态调整数组的大小。 - LinkedList是基于链表实现的,每个元素都包含一个指向前一个和后一个元素的引用。 - Vector也是基于数组实现的动态数组,类似于ArrayList,但是它是线程安全的。 2. 线程安全性: - ArrayListLinkedList不是线程安全的,多个线程同时访问时需要外部同步控制。 - Vector是线程安全的,它的每个方法都使用了synchronized关键字进行同步,可以在多线程环境下使用。 3. 性能: - ArrayList的性能比LinkedList好,因为它直接通过索引访问元素,而LinkedList需要遍历链表才能找到指定位置的元素。 - Vector由于需要进行同步控制,性能相对较差。 4. 插入和删除操作: - ArrayList在末尾插入和删除元素的性能较好,但在中间或开头插入和删除元素时,需要移动其他元素。 - LinkedList在任意位置插入和删除元素的性能较好,因为只需更改节点的引用。 5. 使用场景: - 如果需要频繁访问集合中的元素,并且对数据的增删操作较少,可以选择ArrayList。 - 如果需要频繁进行插入和删除操作,或者需要使用栈、队列等数据结构,可以选择LinkedList。 - 如果需要在多线程环境中使用,可以选择Vector。 总结:ArrayList适用于读取操作频繁的场景,LinkedList适用于频繁插入、删除操作的场景,Vector适用于多线程环境。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值