学习List接口实现类 ArrayList  Vector  LinkedList

List接口的实现类中最经常使用最重要的就是这三个:ArrayList、Vector、LinkedList。

JDK中这三个类的定义:

1、ArrayList<E>:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

/**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

2、 Vector<E>:
public class Vector<E>extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * The array buffer into which the components of the vector are
     * stored. The capacity of the vector is the length of this array buffer,
     * and is at least large enough to contain all the vector's elements.
     *
     * <p>Any array elements following the last element in the Vector are null.
     *
     * @serial
     */
    protected Object[] elementData;

3、LinkedList<E>:

public class LinkedList<E>extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{   // 在序列化这个对象的时候这个变量不会被这样序列化
    transient int size = 0;

/**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

/**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;

4、从这三个类定义就能够看出一些信息:

(1)、三个都直接实现了AbstractList这个抽象类

(2)、ArrayList和Vector都实现了RandomAccess接口。而LinkedList没有。这是什么意思呢?

在JDK 中,RandomAccess接口是一个空接口,所以它没有实际意义。就是一个标记,

标记这个类支持高速随机訪问,所以,arrayList和 vector是支持随机訪问的,可是LinkedList不支持持

(3)、serializbale接口表明他们都支持序列化。

5、以下具体说说List的这三个实现:

(1)、 查看实现源代码会发现这三个里面,ArrayList和Vector使用了数组的实现,相当于封装了对数组的操作。这也正是他们可以支持高速随机訪问的原因,多说一句,JDK中全部基于数组实现的数据结构都可以支持高速随机訪问。

ArrayList和Vector的实现上差点儿都使用了同样的算法,他们的主要差别就是ArrayList没有对不论什么一个方法做同步处理,所以不是线程安全的;而Vector中大部分方法都做了线程同步所以是线程安全的。

(2)、LinkedList使用的是双向循环链表的数据结构。因为是基于链表的。所以无法法实现随机訪问的,仅仅能顺序訪问,这也正是它没有实现RandomAccess接口的原因。

(3)、因为ArrayList、Vector和LinkedList所採用的数据结构不同。注定他们适用的是全然不同的场景。

通过阅读这几个类的源代码,我们能够看到他们实现的不同。

ArrayList和Vector基本一样,我们就用ArrayList和LinkedList做对照。

在末尾添加一个元素

6、ArrayList中的add方法实现例如以下:

/**
     * Appends the specified element to the end of this list.
     *将元素加入到list的最后
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        // 推断容量

ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

这种方法做两件事情,首先确保数组空间足够大。然后在数组末尾添加元素而且通过后++使得完毕size+1

从这个代码能够看出,假设数组空间足够大,那么仅仅是数组的add操作就是O(1)的性能,很高效。

7、在看看ensureCapacityInternal这种方法的实现:

private void ensureCapacityInternal(int minCapacity) {
        modCount++;
        // overflow-conscious code。假设空间不够则扩容也就是又一次创建一个Object[]对象
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

8、grow(int minCapacity)方法创建数组并将原来的数据复制到新数组中

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 使用移位运算,提高效率

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

能够看出。假设数组空间不够,那么这种方法就会做数组扩容和数组复制操作,看上面,JDK利用移位运算符进行扩容计算,>>1右移一位表示除2,所以newCapacity就是扩容为原来的1.5倍。

9、这里的代码都是JDK1.7中的实现,JDK1.7对1.6的非常多代码做了优化。比方上面这段扩容代码,在JDK1.6中上面的是直接除2,显然。移位运算要更高效。

10、在看看LinkedList中的add方法:

(1)、add(E e):

/**
     * Appends the specified element to the end of this list.
     *
     * <p>This method is equivalent to {@link #addLast}.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        linkLast(e);
        return true;
    }
(2)、linkLast(E e) :

/**
     * Links e as last element.
     */
    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++;
    }

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

从这段add代码能够看出。LinkedList因为使用了链表。所以不须要进行扩容,直接把元素加到链表最后,把新元素的前驱指向之前的last元素。并把last元素指向新元素就能够了。

这也是一个O(1)的性能。

在任何位置插入元素

11、ArrayList中的实现例如以下:

(1)、 add(int index, E element)

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

(2)、ensureCapacityInternal(int minCapacity)

private void ensureCapacityInternal(int minCapacity) {
        modCount++;
        // overflow-conscious code,假设数组长度不够则进行扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

(3)、grow(int minCapacity)

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }

这段代码,首先先检查数组容量,容量不够先扩容。然后把index之后的数组往后挪一个。最后在index位置放上新元素。因为数组是一块连续内存空间,所以在任何位置插入。都会导致这个其后数组后挪一位的情况。须要做一次数组复制操作,非常明显,假设有大量的随机插入,那么这个数组复制操作开销会非常大。并且插入的越靠前,数组复制开销越大。

12、LinkedList中的实现:

(1)、add(int index, E element)

/**
     * 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));
    }

(2)、linkBefore(E e, Node<E> succ)
 /**
     * 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++;
    }

(3)、 Node<E> node(int index)

/**
     * Returns the (non-null) Node at the specified element 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;
        }
    }

这段代码。取到原先index处节点的前驱。变成新节点的前驱,同一时候把原先index变成新节点的后驱,这样就完毕了新节点的插入。

这个就是链表的优势。不存在数据复制操作,性能和在最后插入是一样的。

小结:

从上面的源代码剖析能够看出这三种List实现的一些典型适用场景,假设常常对数组做随机插入操作,特别是插入的比較靠前,那么LinkedList的性能优势就很明显。而假设都仅仅是末尾插入,则ArrayList更占领优势。假设须要线程安全。则使用Vector或者创建线程安全的ArrayList。

在使用基于数组实现的ArrayList 和Vector 时我们要指定初始容量。由于我们在源代码中也看到了,在加入时首先要进行容量的推断,假设容量不够则要创建新数组。还要将原来数组中的数据拷贝到新数组中。这个过程会减低效率而且会浪费资源。

转载于:https://www.cnblogs.com/mfrbuaa/p/5157768.html

List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源代码解析相关推荐

  1. Java集合(4)--List接口及其实现类ArrayList、LinkedList和Vector

    文章目录 List接口概述 List接口常用方法 ArrayList实现类 LinkedList实现类 Vector实现类 List接口概述 List集合类中元素有序.且可重复,集合中的每个元素都有其 ...

  2. java vector实现的接口_java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析...

    java面试中经常被问到list常用的类以及内部实现机制,平时开发也经常用到list集合类,因此做一个源码级别的分析和比较之间的差异. 首先看一下List接口的的继承关系: list接口继承Colle ...

  3. java vector实现的接口_java的List接口的实现类 ArrayList,LinkedList,Vector 的区别

    Java的List接口有3个实现类,分别是ArrayList.LinkedList.Vector,他们用于存放多个元素,维护元素的次序,而且允许元素重复. 3个具体实现类的区别如下: 1. Array ...

  4. 16.集合框架(ArrayList,Vector,LinkedList,泛型(Generic),可变参数,增强for循环)

    1.ArrayList存储字符串并遍历 JDK1.8新增的一个方法也能遍历集合 void forEach(Consumer<? super E> action) 执行特定动作的每一个元素的 ...

  5. java:集合(Collection【List(ArrayList Vector LinkedList)、set】、Map【hashMap、treeMap、hashtable、properties】)

    目录 集合的框架体系 一.Collection接口和常用方法 1.1   List接口和常用方法 1.1.1   ArrayList底层结构和源码分析 1.1.2 Vector底层结构 1.1.3 L ...

  6. 【转】ArrayList Vector LinkedList 区别与用法

    ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢 ...

  7. 【Groovy】集合声明与访问 ( 使用 [] 创建 ArrayList 和 LinkedList 集合 | 集合赋初值 | 使用下标访问集合 | 使用 IntRange 作为下标访问集合 )

    文章目录 一.使用 [] 创建集合 1.使用 [] 创建 ArrayList 集合 2.使用 [] 创建 LinkedList 集合 二.访问集合中的元素 1.集合赋初值 2.使用下标访问集合元素 ( ...

  8. Java集合部分学习+源码解析

    Java集合 对象的容器,实现了对对象常用的操作,类似数组功能. 集合中的数据都是在内存中,当程序关闭或者重启后集合中的数据就会丢失,所以说是临时存储数据的容器 集合整体框架 Collection:单 ...

  9. 【Java面试题】37 说出ArrayList,Vector, LinkedList的存储性能和特性

    ArrayList和Vector都是使用数组方式存储数据,此 数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插 ...

最新文章

  1. 来了解下AbstractList
  2. SWT 下菜单与子菜单添加的实现(详细图解)
  3. Django连接postgresql数据库
  4. pandas: DataFrame在数据处理时一些常用的操作汇总
  5. 浅析Kerberos原理,及其应用和管理
  6. 可以获取get post url 传递参数的统一方法
  7. 秋色园QBlog技术原理解析:开篇:整体认识(一)
  8. OpenCV-图像阴影调整
  9. 人工智能-10种机器学习常见算法
  10. 谷歌大脑2017总结下篇:Jeff Dean梳理6大领域研究
  11. javascript案例10——下拉菜单
  12. 一文学会如何做电商数据分析(附运营分析指标框架)
  13. centos7下载,centos iso文件下载
  14. 浅析Tone mapping
  15. 笔记:分布式大数据技术原理(一)Hadoop 框架
  16. 【C++】智力题总结
  17. Windows7UltimateSP1x64安装及一些设置
  18. java memcached incr_Redis与Memcached的incr/decr差异对比
  19. 软件开发综合实践实习小结
  20. iOS企业证书的申请教程

热门文章

  1. 从菜鸟成为数据科学家的养成方案
  2. jQuery导航切换功能
  3. 神奇的JavaScript之正则
  4. create tablespace 与 heap_insert 函数
  5. 编译php的时候,报configure: error: mcrypt.h not found. Please reinstall libmcrypt.错误的解决办法...
  6. .Net Discovery 系列之二--string从入门到精通(下)
  7. 网站设计大访问量应用的解决方案
  8. Ubuntu/Fedora高版本安装海思SDK的方法
  9. arm-linux-gcc 4.7.4 源码编译 手工制作
  10. heima Oracle day2