1. ArrayList 和 Vector 的区别

  ArrayList和Vector底层实现原理都是一样得,都是使用数组方式存储数据

  Vector是线程安全的,但是性能比ArrayList要低。

  ArrayList,Vector主要区别为以下几点:

   (1):Vector是线程安全的,源码中有很多的synchronized可以看出,而ArrayList不是。导致Vector效率无法和ArrayList相比;

      (2):ArrayList和Vector都采用线性连续存储空间,当存储空间不足的时候,ArrayList默认增加为原来的50%,Vector默认增加为原来的一倍;

   (3):Vector可以设置capacityIncrement,而ArrayList不可以,从字面理解就是capacity容量,Increment增加,容量增长的参数。

 

2.说说 ArrayList,Vector, LinkedList 的存储性能和特性

  ArrayList采用的数组形式来保存对象,这种方法将对象放在连续的位置中,所以最大的缺点就是插入和删除的时候比较麻烦,查找比较快;

  Vector使用了sychronized方法(线程安全),所以在性能上比ArrayList要差些.

  LinkedList采用的链表将对象存放在独立的空间中,而且在每个空间中还保存下一个链表的索引。使用双向链表方式存储数据,按序号索引数据需要前向或后向遍历数据,所以索引数据慢,是插入数据时只需要记录前后项即可,所以插入的速度快。

 

3.快速失败 (fail-fast) 和安全失败 (fail-safe) 的区别是什么?

  1.快速失败

  原理是:

        迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hasNext()或next()遍历下一个元素之前,都会先检查modCount变量是否为expectmodCount值。如果是的话就返回遍历;否则抛出异常,终止遍历。

  查看ArrayList源码,在next方法执行的时候,会执行checkForComodification()方法。

       

复制代码
        @SuppressWarnings("unchecked")         public E next() {             checkForComodification();             int i = cursor;             if (i >= size)                 throw new NoSuchElementException();             Object[] elementData = ArrayList.this.elementData;             if (i >= elementData.length)                 throw new ConcurrentModificationException();             cursor = i + 1;             return (E) elementData[lastRet = i];         }
复制代码
复制代码
        final void checkForComodification() {             if (modCount != expectedModCount)                 throw new ConcurrentModificationException();         }
复制代码

  这里异常的抛出条件是modCount != expectedModCount这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedModCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作,这个异常只建议用于检测并发修改的bug。

  2.安全失败

    采用安全失败机制的集合容器,在遍历时不是直接在集合上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

  原理:

          由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所做的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException,例如CopyOnWriteArrayList。

  缺点:

          基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容。即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

  场景:

          Java.util.concurrent包下的容器都是安全失败的,可以在多线程下并发使用,并发修改。

        快速失败和安全失败都是对迭代器而言的。快速失败:当在迭代一个集合时,如果有另外一个线程在修改这个集合,就会跑出ConcurrentModificationException,java.util下都是快速失败。安全失败:在迭代时候会在集合二层做一个拷贝,所以在修改集合上层元素不会影响下层。在java.util.concurrent包下都是安全失败。

 

4.HashMap 的数据结构

  HashMap的主干类是一个Entry数组(jdk1.7) ,每个Entry都包含有一个键值队(key-value).

  我们可以看一下源码:

复制代码
static class Entry<K,V> implements Map.Entry<K,V> {         final K key;         V value;         Entry<K,V> next;//存储指向下一个Entry的引用,单链表结构