文章出自:听云博客java
Java collection是java提供的工具包,包含了经常使用的数据结构:集合、链表、队列、栈、数组、映射等。web
Java集合主要能够划分为4个部分:List列表、Set集合、Map映射、工具类(Iterator、Arrays和Collections)。面试
Java collection 结构图数组
经过上图咱们能够看出安全
Collection是一个interface 数据结构
Collection有List和Set两大分支。多线程
List<E>是一个队列,根据下标索引,第一个元素的下标是0,List的实现类有LinkedList, ArrayList, Vector, Stack。List是有序的队列,List中能够有重复的值。dom
Set<E>是一个集合,SET中的值是惟一的,咱们常常会遇到List去重的问题,把List转为SET就能够快速实现 Set的实现类有HastSet和TreeSet。HashSet。其中TreeSet是有序的。函数
Ma<K,V>是一个interface,即key-value键值对。Map中的每个元素包含“一个key”和“key对应的value”。 工具
AbstractMap是个抽象类,它实现了Map接口中的大部分API。而HashMap,TreeMap,WeakHashMap都是继承于AbstractMap。
Iterator。它是遍历集合的工具,咱们常用Iterator迭代器来遍历集合。Collection的实现类都要实现iterator()函数,返回一个Iterator对象。
抽象类AbstractCollection、AbstractList、AbstractSet、AbstractMap是抽象类,他们都实现了各自的大部分方法,咱们直接继承Abstract类就能够省去重复编码相同的方法 。PS当时来面试的时候被问到这个问题居然一下没想起来。
一、List 是一个接口,它继承于Collection的接口。它表明着有序的队列。
二、AbstractList 是一个抽象类,它继承于AbstractCollection。AbstractList实现List接口中除size()、get(int location)以外的函数。
三、AbstractSequentialList 是一个抽象类,它继承于AbstractList。AbstractSequentialList 实现了“链表中,根据index索引值操做链表的所有函数”。
四、ArrayList, LinkedList, Vector, Stack是List的4个实现类。
ArrayList 是一个数组队列。它由数组实现,实现了RandomAccess, Cloneable, java.io.Serializable接口,因此能够随便访问,克隆,序列化,随机访问效率高,随机插入、随机删除效率低。
LinkedList 是一个双向链表。它也能够被看成堆栈、队列或双端队列进行操做。LinkedList随机访问效率低,但随机插入、随机删除效率低。
Vector 是矢量队列,和ArrayList同样,它也是一个动态数组,由数组实现。可是ArrayList是非线程安全的,而Vector是线程安全的。
Stack 是栈,继承于Vector。栈的特色是:先进后出(First In Last Out)。
List和Vector不一样,ArrayList中的操做不是线程安全的!因此,建议在单线程中才使用ArrayList,而在多线程中能够选择Vector或者CopyOnWriteArrayList。
一、若是涉及到“栈”、“队列”、“链表”等操做,应该考虑用List,具体的选择哪一个List,根据下面的标准来取舍。
二、对于须要快速插入,删除元素,应该使用LinkedList。
三、对于须要快速随机访问元素,应该使用ArrayList。
四、对于“单线程环境” 或者 “多线程环境,但List仅仅只会被单个线程操做”,此时应该使用非同步的类(如ArrayList)。
五、对于“多线程环境,且List可能同时被多个线程操做”,此时,应该使用同步的类(如Vector)。
fail-fast 机制是java集合(Collection)中的一种错误机制。当一个线程遍历某集合时,这个集合的值被其它线程改变,该线程就会抛出ConcurrentModificationException异常。
fail-fast示例。
package Test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class FastFailEX { private static List<Integer> list = new ArrayList<Integer>(); public static void main(String[] args) { //使用两个线程操做list new ThreadA().start(); new ThreadB().start(); } private static void print() { System.out.println(""); Integer value = null; Iterator<Integer> iter = list.iterator(); while(iter.hasNext()) { value = (Integer)iter.next(); System.out.print(value+", "); } } //向list添加元素 private static class ThreadA extends Thread { public void run() { for(int i=0;i<10;i++){ list.add(i); print(); } } } //向list添加元素 private static class ThreadB extends Thread { public void run() { for(int i=10;i<20;i++){ list.add(i); print(); } } } }
运行结果:
结果说明:
当某一个线程遍历list的过程当中,list的内容被另一个线程所改变了;就会抛出ConcurrentModificationException异常,产生fail-fast事件。
ConcurrentModificationException是在操做Iterator时抛出的异常。咱们先看看Iterator的源码。在AbstractList.java中
经过以上代码段咱们看到两点
一、执行next()时,要先判断iterator返回的对象中的modCount”和“当前的modCount”是否相等
二、若是不相等,则抛回异常
接下来咱们要知道在什么状况下 modCount!= expectedModCount
咱们来看ArrayList.java中的代码
咱们如今知道,只要修改集合中的元素个数时,都会改变modCount的值。
添加时在决定是否扩空list前修改modCount,删除元素时直接修改
至此,咱们就彻底了解了fail-fast是如何产生的。
即,当多个线程对同一个集合进行操做的时候,某线程访问集合的过程当中,该集合的内容被其余线程所改变(即其它线程经过add、remove、clear等方法,改变了modCount的值);这时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
使用CopyOnWriteArrayList 就不会产生fail-fast
上源码
从中,咱们能够看出:
CopyOnWriteArrayList是本身实现了Iterator 为COWIterator。
ArrayList的Iterator调用next()时,会调用checkForComodification()比较expectedModCount和modCount的大小;CopyOnWriteArrayList的Iterator实现类中,没有checkForComodification(),因此不会抛出ConcurrentModificationException异常。
Map是什么:public interface Map<K,V> { }
Map 是一个键值对(key-value)映射接口。Map映射中不能包含重复的键;每一个键最多只能映射到一个值。
Map 接口提供三种collection 视图,容许以键集、值集或键-值映射关系集的形式查看某个映射的内容。
Map 映射顺序。有些实现类,能够明确保证其顺序,如 TreeMap;另外一些映射实现则不保证顺序,如 HashMap 类。
Map 的实现类应该提供2个“标准的”构造方法:第一个,void(无参数)构造方法,用于建立空映射;第二个,带有单个 Map 类型参数的构造方法,用于建立一个与其参数具备相同键-值映射关系的新映射。实际上,后一个构造方法容许用户复制任意映射,生成所需类的一个等价映射。尽管没法强制执行此建议(由于接口不能包含构造方法),可是 JDK 中全部通用的映射实现都听从它。
一、Map 是映射接口,Map中存储的内容是键值对(key-value)。
二、AbstractMap 是继承于Map的抽象类,它实现了Map中的大部分API。其它Map的实现类能够经过继承AbstractMap来减小重复编码。
三、SortedMap 是继承于Map的接口。SortedMap中的内容是排序的键值对,排序的方法是经过比较器(Comparator)。
四、NavigableMap 是继承于SortedMap的接口。相比于SortedMap,NavigableMap有一系列的导航方法;如"获取大于/等于某对象的键值对"、“获取小于/等于某对象的键值对”等等。
五、TreeMap 继承于AbstractMap,且实现了NavigableMap接口;所以,TreeMap中的内容是“有序的键值对”, 它是经过红黑树实现的。它通常用于单线程中存储有序的映射。
六、HashMap 继承于AbstractMap,没实现SortedMap或NavigableMap接口;所以,HashMap的内容是无序的键值对。
七、Hashtable继承于Dictionary(Dictionary也是键值对的接口),实现Map接口;所以,Hashtable的内容也是“键值对,是无序的”。 Hashtable是线程安全的。
八、WeakHashMap 继承于AbstractMap。它和HashMap的键类型不一样,WeakHashMap的键是“弱键”, 当“弱键”被GC回收时,它对应的键值对也会被从WeakHashMap中删除。JVM提供的弱引用
Set 是继承于Collection的接口。它是一个不容许有重复元素的集AbstractSet 是一个抽象类,它继承于AbstractCollection,AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利。
HastSet 和 TreeSet 是Set的两个实现类。
HashSet中的元素是无序的。
TreeSet中的元素是有序的,不支持快速随机遍历,只能经过迭代器进行遍历。
在Java集合中,咱们一般都经过 “Iterator(迭代器)” 或 “Enumeration(枚举类)” 去遍历集合
Enumeration是一个接口,它的源码以下
Iterator也是一个接口,它的源码以下:
一、函数接口不一样
Enumeration只有2个函数接口。经过Enumeration,咱们只能读取集合的数据,而不能对数据进行修改。
Iterator只有3个函数接口。Iterator除了能读取集合的数据以外,也能数据进行删除操做。
二、Iterator支持fail-fast机制,而Enumeration不支持。
Iterator和Enumeration性能对比
package Test;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Random;
public class IteratorEnumerationEX { public static void main(String[] args) { int val; Random r = new Random(); Hashtable<Integer, Integer> table = new Hashtable<Integer, Integer>(); for (int i=0; i<100000; i++) { val = r.nextInt(100); table.put(i, val); } iterateHashtable(table) ; enumHashtable(table); } private static void iterateHashtable(Hashtable<Integer, Integer> table) { long startTime = System.currentTimeMillis(); Iterator<Entry<Integer, Integer>> iter = table.entrySet().iterator(); while(iter.hasNext()) { iter.next(); } long endTime = System.currentTimeMillis(); countTime("iterate",startTime, endTime); } private static void enumHashtable(Hashtable<Integer, Integer> table) { long startTime = System.currentTimeMillis(); Enumeration<Integer> enu = table.elements(); while(enu.hasMoreElements()) { enu.nextElement(); } long endTime = System.currentTimeMillis(); countTime("enum",startTime, endTime); } private static void countTime(String type,long start, long end) { System.out.println(type+":"+(end-start)+"ms"); } }
输出结果
由于Iterator支持fail-fast因此作操做多一些性能也相对慢一些
原文连接:http://blog.tingyun.com/web/article/detail/268