Java常用集合类总结

       这篇文章主要是对常用的集合的特点,数据结构和实现原理有个初步的认识,抽空再详细的通过源码来介绍每个集合的原理~多谢各位的关注!

        在介绍常用集合类之前先了解一下集合类结构体系:从类的继承结构来说,可以分为两大类,一类是继承自Collection接口,这类集合包含List、Set和Queue等集合类。另一类是继承自Map接口,这主要包含了哈希表相关的集合类

一、List集合

         List集合是单列集合体系之一,它的特点有三个:List集合及其实现类全部都是有索引

                                                                                      List集合及其实现类全部都是可以存储重复元素

                                                                                      List集合及其实现类全部都是元素存取有序

注:以下提到的List集合都符合这几个特点,就不再重复!

 

     1.ArrayList集合

              ArrayList是List使用中最常用的实现类,是基于数组实现的,是一个动态数组,其容量能自动增长

              主要特点查询速度快,效率高,但增删慢,线程不安全

              数据结构数组,并且数组默认大小为10;

              实现原理:基于Array,它主要就是实现List接口、底层使用数组保存所有元素。其操作基本上是对数组的操作。对数组的扩容就是他的实现原理

                      jdk1.8的扩容算法:newCapacity = oldCapacity + ( oldCapacity >> 1 ) ;   // oldCapacity >> 2  移位运算,此处相当于oldCapacity除以2,但是 >> 这种写法更加高效

                      jdk1.6的扩容算法:newCapacity = ( oldCapacity * 3 ) / 2 +1 ;   扩容前的容量大小乘以三后再加一

                     参数介绍:newCapacity 是扩容后的容量大小,oldCapacity 是扩容前的大小

     2.Vector集合

              Vector的底层也是通过数组实现的,默认大小也是10。

              主要特点查询快,增删慢  , 线程安全(可以用在多线程),但是效率低

              数据结构数组,并且数组默认大小为10;

              实现原理:创建对象与ArrayList类似,但有一点不同,它可以设置扩容是容量增长大小

     3.LinkedList集合

              LinkedList和ArrayList一样是集合List的实现类,LinkedList底层是一个双向链表,除了当做链表使用外,它也可以被当作堆栈、队列或双端队列进行操作。

              主要特点:它增删快,效率高,但是查询慢,线程不安全

              数据结构:双向链表,所以没有容量大小的定义,只有上个节点,当前节点,下个节点,每个节点都有一个上级节点和一个下级节点。

              实现原理:继承了AbstractSequentialList类,实现了List接口,基于列表的,LinkedList的没有扩容方法!默认加入元素是尾部自动扩容!

二、Set集合

           Set集合是单列集合体系之一,它的特点有三个:不可以存储重复元素;

                                                                                         没有索引,不能使用普通for循环遍历

                                                                                     

注:以下提到Set集合都符合这几个特点,就不再重复!

       1.HashSet集合

            HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null元素基于HashMap实现,API也是对HashMap的行为进行了封装;底层是 哈希表结构 (可查看 哈希表结构 ),所以 查询非常快,属于 无序集合

              主要特点:底层是哈希结构,创建最慢、查询最快、增删最快;无序;不可重复元素;无索引

              数据结构:底层是一个Hash表=主结构(数组)+分支(单链表)

              实现原理: 对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成.所以细看HashMap的底层实现原理

     

       2.TreeSet集合

          TreeSet是SortedSet接口的唯一实现,可以确保集合元素处于排序状态,基于TreeMap实现。TreeSet并不是根据元素的插入顺序进行排序,而是根据元素实际值来进行排序的。

              主要特点:底层是红黑树的数据结构,有两种排序规则,自然排序( Comparator )和定制排序,线程不安全,可被序列化

              数据结构:底层是平衡二叉树结构

              实现原理: 根据红黑树存储数据的原理,小的存左边,大的存右边,红黑交替。唯一性同样需要重写hashCode和equals()方法。根据构造方法不同,分为自然排序(无参构造)和比较器排序(有参构造),自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同,不需要存储;比较器排需要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法;

       3.LinkedHashSet集合

           LikedHashSet介于HashSet和TreeSet之间。基于双向链表实现的哈希表,保留了元素插入顺序。它是HashSet的子类。

              主要特点:元素不重复,可预测的迭代顺序,线程不安全

              数据结构:底层是双向链表+hash表

              实现原理:  对于LinkedHashSet而言,它继承与HashSet、又基于LinkedHashMap来实现的。实现原理详解下面LinkedHashMap。

三、Map集合

          Map是双列集合,用于保存具有映射关系的数据,Map里保存着两组数据:key和value,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。  它的主要三大特点: 1)、Map集合中的 key与value的数据类型 可以相同,也可以不同
                                                     2)、Map集合中的key不允许重复,但是value允许重复
                                                     3)、Map集合中,key和value是一一对应的

注:以下提到Map集合都符合这几个特点,就不再重复!

       1.HashMap集合

             HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。

              主要特点:双列集合;底层是哈希结构创建最慢、查询最快、增删最快;无序;无索引;

              数据结构:JDK1.7及之前:数组+链表                JDK1.8:数组+链表+红黑树   默认初始数组长度为16

              实现原理:  HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。

                                                1.当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,计算并返回的hashCode是用于找到Map数组的bucket位置来储存Node 对象。这里关键点在于指出,HashMap是在bucket中储存键对象和值对象,作为Map.Node 。

                                                2.若查找的哈希表位置为空,则直接储存。如果哈希表位置不为空,则利用equals方法比较它的key,结果为true则覆盖value。结果为false则以链表的方式接到后面。如果链表长度超过阀值( TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表

                                                3. 当哈希表实际节点数达到容量的75%的时候需要调用resize方法进行扩容。扩容的过程:满足的必要条件就是1.当前数据存储的数量(即size())大小必须大于等于阈值;2.当前加入的数据是否发生了hash冲突。

                                               HashMap的默认容量时16,负载因子为0.75,所以阈值为12,。当HashMap储存程度达到容量的75%时,将会创建原来大小两倍的数组,并将数组重新hash放入新的bucket中,所以频繁的扩容会消耗性能。至于扩容到原来的两倍是为了避免内存碎片,提高运算速度,通过高位异或,提高散列度,降低冲突。

       2.TreeMap集合

           TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中,在对集合进行遍历的时候,每个元素将自动按照排序后的顺序呈现, 实现了NavigableMap接口,意味着拥有了更强的元素搜索能力。

              主要特点:双列集合;底层是红黑树结构可自定义排序规则,支持序列化操作

              数据结构平衡二叉树

              实现原理:TreeMap的实现是红黑树算法的实现,

添加节点的过程如下:

       1、以根节点为初始节点进行检索。

       2、与当前节点进行比对,若新增节点值较大,则以当前节点的右子节点作为新的当前节点。否则以当前节点的左子节点作为新的当前节点。

       3、循环递归2步骤知道检索出合适的叶子节点为止。

       4、将新增节点与3步骤中找到的节点进行比对,如果新增节点较大,则添加为右子节点;否则添加为左子节点。

       3.HashTable集合

          和HashMap一样,Hashtable 也是一个散列表,它存储的内容是键值对(key-value)映射。和hashMap最大的区别就是这是线程安全的

              主要特点:双列集合,线程安全,可序列化,不允许null做键值和value,基本和hashMap一样,只不过效率低

              数据结构哈希表(数组+链表),默认数组长度为11

              实现原理:HashTable中的内部数组的初始容量是11,也是使用75%扩容,方式为(原容量*2+1)。它也是通过"拉链法"实现的哈希表,和HashMap存操作元素的原理也几乎一样,只不过它的很多方法都加入了synchronized关键字,所以线程安全

       4.ConcurrentHashMap集合

           HashMap是使用频率很高的一种数据结构,经常被用作本地缓存,但是在多线程环境下,对其操作是不安全的,所以ConcurrentHashMap是J.U.C包里面提供的一个线程安全并且高效的HashMap。是Map的派生类,所以api的使用基本和Hashmap是类似。

              主要特点:

              数据结构数组+链表+红黑树(jdk1.8之后)

              实现原理:ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEntry 用来封装映射表的键 / 值对;Segment 用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶。每个桶是由若干个 HashEntry 对象链接起来的链表。一个 ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组。每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。每个ConcurrentHashMap 类会创建16个并发的segment,每个segment里面包含多个Hash表,每个Hash链都是有HashEntry节点组成的。  如果键能均匀散列,每个 Segment 大约守护整个散列表中桶总数的 1/16

   为什么ConcurrnetHashMap 为什么高效?  1. 纯内存操作,本地缓存,无磁盘IO;
                                                                          2.优秀的数据结构,使时间复杂度降到了最低O(1)
                                                                          3.HashtEntry的不变性final + 读写可见性volatile,降低锁的需求,使读效率高;
                                                                          4.锁优化Synchronized代替ReentrantLock锁,cas机制和源码中的 自旋操作for(;;),读多写少的场景避免了线程的阻塞;
                                                                          5.采用粒度锁分离实现多个线程间的并发写操作,提高效率;
                                                                          6.多线程并发扩容,并且支持无阻塞读和更新
                                                                          7.优秀的hash算法,使数据尽量分散均匀;
                                                                          8.细节设计的也好,例如元素个数的统计,位操作代替&运算,链表和红黑树的转换等等决定了效率高;


 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值