深入理解JAVA集合------List体系

List体系如下:

 

类与接口说明:

   1、Collection:高度抽象出来的集合、定义某一类集合所具有的基本的方法、标准。

   2、Iterable:标识性接口、要求子类提供获取Iterator方法、并且要实现Iterator具有的几个方法。

   3、Iterator:迭代器、用于迭代Collection中元素、要求子类必须实现获取Iterator的方法。

   4、List:以队列的形式存储、操作元素、定义了这种形式的集合所具有的基本方法、以及方法的定义。要求List实现类集合中每个元素都有索引、索引值从0开始。

   5、AbstractCollection:Collection的实现类、要求需要实现Collection接口的类都必须从它继承、目的是用于简化编程。

   6、AbstractList:继承AbstractCollection、实现List接口中定义方法、目的也是简化编程、并且其内部提供了获取Iterator、ListIterator的方法。

   7、AbstractSequencedList:继承AbstractList、使得List支持有序队列、比如链表形式存储操作元素。

   8、ArrayList:继承AbstractList、以动态数组的形式存储、操作元素。

   9、LinkedList:继承AbstractSequencedList、实现Deque、List接口、以双向链表的形式存储、操作元素。

   10、Vector:继承AbstractList、以动态数组的形式存储、操作元素、线程安全。

 

ArrayList 与 LinkedList对比:

   相同点:

      1)都直接或者间接继承了AbstractList,所以都支持以索引的方式操作元素;

      2)都不需要担心容量问题,ArrayList是通过动态数组的形式来保存数据的,当容量不足会自动扩容。(注:ArrayList初始化容量为10,扩容代码如下:

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

      3)都是线程不安全的、一般用于单线程的环境下、要想在并发的环境下使用可以使用Collections工具类包装。

   不同点:

      1)ArrayList是通过动态数据保存数据的,LinkedList是通过双向链表保存数据的;

      2)相对与ArrayList而言,LinkedList继承了AbstractSequentialList,而AbstractSequentialList继承了AbstractList,所以使得LinkedList不仅保留了以索引操作元素的功能,同时实现了双向链表所具有的功能;

      3)对集合中元素进行不同的操作效率不同、LinkedList善于删除、添加元素、ArrayList善于查找元素。本质就是不同数据结构之间差异。

ArrayList 与 Vector的对比:

   相同点:

      1)都是继承AbstractList、拥有相同的方法的定义;

      2)内部都是以动态数组来存储、操作元素的、并且都可以自动扩容。

   不同点:

      1)线程安全:ArrayList是线程不安全的、适用于单线程的环境下、Vector是线程安全的、使用与多线程的环境下;

      2)构造方法:Vector有四个构造方法、比ArrayList多一个可以指定每次扩容多少的构造方法;

      3)扩容问题:每当动态数组元素达到上线时、ArrayList扩容为1.5倍,Vector为2倍;Vector扩容代码如下:

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        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);
    }

      4)效率问题:因为Vector要同步方法、这个是要消耗资源的、所以效率会比较低下;

数组、ArrayList、LinkedList、Vector操作元素对比:

   实现机制  查询  写  迭代操作
 数组  连续内存区域保存元素数据  1  不支持  不支持
 ArrayList  以数组保存数据  2  2  2
 LinkedList  以链表保存数据  4  1  1
 Vector  以数组保存数据  3  3  3

 

 

 

 

 

    数组牺牲长度变化,直接在内存在开辟固定空间保存数据,所以查询速率最快,但是因为size大小固定,所以不支持写操作。

    a)ArrayList查询的速率比LinkedList的快,两者都是通过索引去查找元素,ArrayList是直接通过index定位到元素位置,而LinkedList是通过二分法确定元素位置范围,再逐个查找,直到找到该元素为止。相比ArrayList     来说LinkedList更耗时,更耗费资源。两者查询元素源码如下:

/**
*ArrayList通过索引查询元素
**/ 
public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

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

/**
*LinkedList通过索引查询元素
**/ 
    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;
        }
    }

但是ArrayList的写操作效率明显低于LinkedList,原因如下:

对于指定index处的插入、删除、ArrayList和LinkedList都是先通过索引查找到指定位置、然后进行下一步的插入删除操作、上面我们知道LinkedList是先通过二分法查找index范围再确定index具体位置、但是ArrayList是直接定位到index处、为什么LinkedList反而快?依然通过源码找原因。

对比上面代码可以看出来ArrayList每当插入一个元素时、都会调用System.arraycopy()将指定位置后面的所有元素后移一位、重新构造一个数组、这是比较消耗资源的、而LinkedList是直接改变index前后元素的上一个节点和下一个节点的引用、而不需要动其他的东西、所以效率很高。

 

ArrayList、Vector都是继承与AbstractList、并且在类结构上没有多少差异、但是因为Vector要同步方法、所以在性能上不如ArrayList、从源码也可以看出Vector许多方法都是使用关键字synchronized修饰的。

posted @ 2018-02-24 09:44  随心-HL  阅读(858)  评论(0编辑  收藏  举报