Java中集合框架的总结

     在学习这块知识的时候觉得内容很多,还有很多比较底层的东西需要理解,当时就觉得头都大了,这几天静下心来,翻了翻书,也查了一些资料,对这块的知识体系,也有了自己的一个框架,所以对此做以总结,此文主要从以下几个方面进行阐述:

Java中集合框架的总结

1.为什么要使用集合框架?

  数组是Java提供的随机访问对象序列的最有效方法,访问元素较快,缺点就是数组的大小自创建之后就固定了,所以集合框架的出现就是为了解决数组定长的问题。

2.什么是集合框架?

   集合框架是一个用来代表和操纵集合的统一架构,Java集合框架主要包括两种类型的容器,Collection 和Map,下面对这两种容器作以详述:

Collection集合:保存单个元素的父接口:下图为Collection及其子类的关系图:

Java中集合框架的总结

在这里,主要对Collection接口子类中的List接口和Set接口作主要介绍:

(1)List接口

        List接口是一个有序的Collection,使用List接口能够精确的控制每个元素插入的位置,能够通过索引来访问List中的元素,并且允许元素可以重复。在List有三个重要的子类:ArrayList、LinkedList、Vector

      三者的异同:

        a. 相同之处:ArrayList 、LinkList、Vector都实现了List接口;

        b.不同之处:

        ArrayList:JDK1.2出现,采用懒加载策略,扩容时都是当前长度的1.5倍,底层数组实现,线程不安全,查找效率高;

        LinkedList:JDK1.2出现,底层使用双向循环链表实现,查询慢,增删快,线程不安全,不存在容量不足的情况,允许有null(空元素);

        Vector:JDK1.0出现,底层使用数组实现,查询块,增删慢,线程安全效率低,容量不足时扩增为当前容量的2倍。

 (2)Set接口:不允许数据重复,实质是穿了马甲的Map

         Set接口下有两个重要的子类:HashSet、TreeSet

       对比HashSet 和TreeSet:

        a.HashSet:不保证集合元素中的顺序,允许包含值为null的元素,但最多只能一个;

          HashSet中元素判重的依据:hashCode()与equals()方法:hashCode()相等的元素equals()不一定相等,equals()相等的元素hashCode()不一定相等。

        b.TreeSet:保证集合中的元素有序,可以实现排序等功能;

        TreeSet有序,序指的是什么?

    ----要使用TreeSet,必须满足以下两个条件之一:

       i)作为TreeSet集合的类,实现Comparable接口(内部接口)

      ii)通过构造方法传入Comparator接口对象(外部排序)----更加灵活,采用策略模式,可以修改排序的规则;

(3)LIst和Set的区别

      a.Set接口实例存储的时无需的,不可重复的数据,List接口实例存储的是有序的,可以重复的元素;

      b.Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变;

      c.List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度,查找元素效率高,插入删除效率低。

Map:保存一对对象的接口(键值对),下图为Map与其子类的关系图:

Java中集合框架的总结

在这里主要对Map接口下的Hashmap、Treemap、HashTable、ConcurrentHashMap做以介绍:

     a.HashMap:元素无序,不可重复,但可以为null(最多只允许一个),底层采用数组和链表结合的数据结构,线程不安全,查找效率高,容量一直为2的n次方(即每次扩充都为原来的2倍);

     b.TreeMap:底层采用二叉树实现,线程不安全;

     c.HashTable:元素无序,不可重复,不可以为null,底层采用数组和链表结合的数据结构,线程安全,查找效率高,2倍扩容

     d.HashTable的优化

     ----ConcurrentHashMap

      a.JDK1.7实现:【基于分段锁Segment来实现,每个Segment都是ReentrantLock的子类】

      i)将哈希表拆分为16个Segment,每个Segment下又是一个小的哈希表;

     ii)关于锁:将原先整表的一把锁细粒度化为每个Segment的一把锁,并且不同Segment之间互不干扰,每个Segment实际上都是ReentrantLock的子类

    iii)扩容机制:Segment初始化之后就无法扩容(默认初始化为16),这里的扩容实际上是Segment对应的每个小的哈希表,并且不同Segment之间的扩容完全隔离。

   b.JDK1.8实现:

     i)结构:与JDK1.8的HashMap如出一辙,也是哈希表+红黑树的底层结构,原先的Segment仍然保留,但是没有实际意,仅仅用作序列化

     ii) 关于锁:将原先锁一片再次细粒度化为只锁桶中的头结点【使用CAS+同步代码块(synchronized)】

   c.JDK1.7 与JDK1.8的对比

    i)结构上:JDK1.7 是基于分段锁的Segment,JDK1.8 是哈希表+红黑树;

    ii)锁的使用:JDK1.7使用Reentrant将Segment上锁,JDK1.8使用CAS+synchronized代码块。

fail-fast:Java.Util.concurrentModificationException(集合并发可修改异常)

   如何产生?

----在迭代遍历集合的时候同时修改结合结构(通过add()、remove())

   产生原因:在集合里边有  modCount(用于存储当前修改集合次数的值)!=expectedModCount(用来取出当前集合修改次数的值),当取得集合迭代器遍历的时候,会先比较这两个值,如果不相等立即抛出异常。

  为什么抛出此异常?

      ----尽量保证在多线程的场景下,数据不会产生脏读(即如果有线程并发修改集合结构时,相同遍历该集合的线程发出一个异常,通知遍历集合的线程 集合数据已经被修改)。

 

HashMap底层原理实现:

参考链接:http://blog.****.net/goosson