经常使用集合类的特色

        集合类是java中比较重要的类,同时也是面试过程中常常涉及到的一类问题,在这里对经常使用的集合类进行一下整理总结。java

      

       集合类结构如图1所示:
面试

                                                          

   图1  类结构算法


         由图1可知,ArrayList、Vector、LinkedList类都是实现了List接口,HashSet、TreeSet实现了Set接口,而HashMap、HashTable和TreeMap都是实现了Map接口。结合上图,分别介绍下各类集合类的特色。数组

         1、实现List接口的集合类
安全

         一、ArrayList是比较经常使用的一个集合类。首先,此类是非线程安全的集合类。同时,此类也是有序的且可重复的,即读取的顺序和保存的顺序是一致的。在构造一个初始的ArrayList对象时,其初始大小为10.那么,随着元素不断的增长,当初始化申请的空间存放不下的话,就要进行申请空间,具体算法以下图所示:数据结构

public void ensureCapacity(int minCapacity) {  
    modCount++;  
    int oldCapacity = elementData.length;  
    if (minCapacity > oldCapacity) {  
        Object oldData[] = elementData;  
        int newCapacity = (oldCapacity * 3)/2 + 1;  //增长50%+1
            if (newCapacity < minCapacity)  
                newCapacity = minCapacity;  
      // minCapacity is usually close to size, so this is a win:  
      elementData = Arrays.copyOf(elementData, newCapacity);  
    }  
 }
           也就是当空间不足时,申请的大小为((oldCapacity * 3)/2 + 1),也就是原来大小的1.5倍。

           二、Vector在非多线程程序中用的很少,这是由其特性决定的。Vector是线程安全的类,也就是同步类(ynchronized)。在其它方面,它是与ArrayList基本上类似的。两者除了线程安全的不一样之外,那么就是ArrayList执行的效率要比Vector高,也就是说Vector牺牲了效率换取了安全性,一样的道理,ArrayList牺牲了安全性而换取了效率。其实两者没法区分哪一个类比那个类更好,最终是取决于你实际的业务,合适的就是最好的。多线程

           三、LinkedList也是常常用到的一个集合类。简单的有名称就能够看出,这是一个基于链表的集合类。那么究竟是不是呢?咱们结合下面的源码来看:this

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;
        }
    }
          由代码能够发现,它存在一个前驱属性(prev)和一个后继属性(next),因而可知这是一个双向链表的结构。一样的,LinkedList也是一个非线程安全的集合类。那么它的特色在哪里呢?因为ArrayList和Vector是基于数组,而LinkedList是基于链表,那么这里就结合他们的这些本质特性来比较小两种类型的集合类的效率。

          首先,增长一个节点数据。这里以ArrayList为例,它增长一个数据后,其后面的节点数据都须要向后移动一个位置,也就是对应的index都须要加1,而LinkedList只须要修改它节点的前驱和后继便可,因此在增长一个数据这个操做过程当中,其效率是要高于ArrayList的。spa

         其次,删除一个节点数据,原理同上,只不过是减小,一样是LinkedList的效率要高于ArrayList。线程

         再次,查询一个节点的数据,对应ArrayList,只须要遍历至该节点便可,儿LinkedList则须要对其前驱和后继也就是地址进行操做,其效率要低于ArrayList,因此ArrayList的效率要高。

         最后,修改一个节点的数据,那么,在修改以前须要先查询出将要修改的节点,因为ArrayList的查询速度要快于LinkedList,因此修改方面的效率天然是ArrayList高于LinkedList的效率。

         综上所述,在增删操做方面,LinkedList的效率要高于ArrayList,而在改查操做方面,则是相反,LinkedList要低于ArrayList。固然,在数据量相对较小的状况下,两者的差距基本上是微乎其微的,可是若是设计到的数据量大的话,那么就要考虑其效率,选择合适的集合类。


         2、实现Set接口的集合类

         一、HashSet集合类,其实经过源码能够发现,HashSet的实现,在底层是基于HashMap实现的,以下代码所示:

public HashSet(Collection<? extends E> c) {
        map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
        addAll(c);
    }
       初始化时,初始化一个负载系数为0.75的HashMap,该集合类的特色是无序、不能add重复的值,其实,这也就是由其底层特性所决定的。

     
       二、TreeSet集合类,TreeSet集合类的实现是基于TreeMap实现的,TreeMap是一种有序二叉树数据结构,基于这种数据结构,数据的查找和操做则效率更高。

      3、实现Map接口的集合类

      一、HashMap集合类,这是一个重要的集合类,HashMap集合类的特色是继承了AbstractMap类,且k值和v值都容许为null,重要的一点是,HashMap类是非同步的,也就是说是非线程安全的类。

    二、HashTable集合类与HashMap集合类相对应,可是HashTable集合类是继承了Dictionary类,与HashMap相反,它的k和v都是不容许为null,最重要的一点是,HashTable类是同步类,也就是线程安全的集合类。因为是线程安全类,效率上可能低于HashMap类。