java基础--总说集合

     在Java的世界里,集合是一个不可或缺的部分,没有集合我们无法实现大批量数据或者变量的存储,但是究竟集合的水有多深,我们还需继续研究.

   先来看一张集合的架构图:

     

    如图所示,Iterator处于最顶层,之后衍生出 Collection和Map两个大类型,在两个不同的类型下,又有不同的集合类型,下面我们就从list,set 和hashTable/hashMa逐一说起:

   PS :collection 是最基本的集合接口,

1.list

     首先我们必须明确,list中存储的数据是可重复的,有顺序的,list使用较广泛的有linkedList和arraylist两种;

    1.1   linkedList

         linkedList内部是以链表的形式来保存集合中的元素的,因此随机访问集合中元素时性能较差,但在插入和删除元素的时候效率会很出色,因为执行这两个操作的时候改变的是集合内部指针的指向.

    1.2  arraylist

       这个就是我们最常使用的数组,也就是说内部存储结构是数组形式,这样存储在arraylist中的元素都有一个索引(也就是下标)来确定元素,所以相对于上述类型,它的查找效率很高,我们直接根据索引号来获取就可.但是,arraylist在删除元素的时候,效率较低,比如要在10个元素的数组中删除,索引为4的元素,执行删除该元素的操作之后,数组需要把索引为5及其以后的元素统一向前移动一位,所以效率会很低;

2.set

     set集合类似于一个罐子,一旦把对象"丢进"集合,集合里多个对象之间没有明显的顺序,但是set集合不允许包含重复元素;那么set集合是如何保证两个相同元素无法被存储进来的呢,set中使用equals方法判断两个元素是否相等,只要两个对象使用equals方法比较之后返回为true,set就不会接受这两个对象,反之,set就会接收并存储两个对象;

      set有三个实现类,hashSet,treeSet和EnumSet,在这三个类中,我们需要明白的是treeSet是有序集合,为什么??类似二叉树的存储思想,treeSet存储的时候是将元素与根元素进行对比,比它小的被放在左子树上,比它大的被放在又子树上.那么问题又来了,它是如何保证树中的元素是有序的?? 在set集合中有一个SortedSet接口,这个接口中有一个comparable的方法,用来比较两个元素,  而treeSet实现了这个接口,所以也就继承到了这个方法,所以在treeSet中放入元素时都会先来调用这个方法,比较出结果之后也就是元素之间有了大小顺序,才会存储.

<span style="font-size:18px;">public class SetTest {
public static void main(String[] args) {
                Set bookSet = new HashSet();
                bookSet.add(new String("2016年7月26日"));
                //再添加一个元素
                boolean result = bookSet.add(new String("2016年7月26日"));
                //由于使用equals方法得到的结果是true,也就是说这两个元素是相同的,所以添加失败,返回false;
                System.out.println(result);
        
                //所以set集合中只有 一个元素:
                System.out.println(bookSet);
        }
}</span>

    执行上述代码之后,输出结果为false,也就是说第二个元素插入失败,这也就是验证了set中元素不允许重复的思想;

     hashset是set接口的典型实现类,大多数使用set集合都是使用这个类,它使用的是hash算法来存储集合中的元素,所以hashset存储时会调用该对象的hashcode方法来得到该对象的hashcode值,根据hashCode值来决定该对象在hashset中的存储位置. 

    提到hashCode,大家有没有想到 arraylist中的索引呢? 那么既然都有索引,为什么不使用数组而使用hashset呢?

    数组中的索引是连续的,并且数组的长度是固定的,也就是说初始化的数组容量, 后期使用的时候不能超过下标,否则会有 下标溢出的异常(java 8中对这个进行了改善),但是hashSet采用每个元素的hashcode作为其索引,从而可以自由增加hashset的长度,并且可以根据元素的hashcode值来访问元素.

3.map

      与hashcode相关的不仅仅是上面提到的hashset,还有map中的两个实现类:hashTable和hashMap,相对于set和list来讲, map中的元素不允许重复,元素之间没有顺序;

      从实现效率上来讲,两者相差无几,但是两者最大的区别在于:

        1)是否线程安全

         hashMap是线程不安全的,而hashTable是线程安全的,它会在每个操作中添加lock关键字对当前代码或者数据加锁,这样保证了线程同步和安全,所以如果有多个线程访问同一个map对象使用hashTable的性能更好;

        2) key和value是否可以为空

        hashTable中不允许null作为key和value,但是从某个角度来讲hashMap可以,但是由于hashMap不能插入相同元素,所以hashMap中只能允许一次null的插入;

       既然我们已经知道hashTable和hashMap的区别,也考虑到hashMap的线程不安全,但是由于hashTable加锁锁定的是整个map对象,所以性能会有所下降,那么有没有另外的解决办法,兼并hashMap的效率和hashTable的线程安全,那就是concurrentHashMap:

       与hashTable相比, concurrentHashMap默认是把 整个map分成16个segment(也就是锁分段的技术),并对每一个segment单独加锁,这样就相当于在hashTable的基础上做了16倍的效率提升:

     

       在hashTable中,lock每次都要锁住整个结构;ConcurrentHashMap就是为了解决这个问题而诞生的。ConcurrentHashMap锁的方式是稍微细粒度的,ConcurrentHashMap将hash表分为16个桶,诸如get,put , remove 等常用操作只锁当前需要用到的桶。所以原来只能有一个线程进入,现在却能同时有16个写线程进入(写线程才需要锁定,而读线程几乎不受限制),并发性的提升显而易见。ConcurrentHashMap也采用了链表作为每一个hash桶中的元素,不过ConcurrentHashMap又有些不同:

    把一个大的map拆分成N个小的HashTable,根据key.hashcode 来决定把key放在哪个"HashTable"中:

   

4.总结  

     介绍完每种集合的不同情况之后,我们从整体上来总结一下每种集合在不同场景下的效率:

 (1)单线程模式下性能测试 ,测试元素100~1000中平均成绩 :

       添加  HashMap效率最高,ArrayList最低,其他的效高的还有Stack、HashSet和Vector,较低的有LinkedList和TreeSet和TreeMap

       删除  HashMap效率最高,LinkedList最低,其他的HashSet、TreeMap和TreeSet效率较高,较低的有Vector、ArrayList和Stack

       查找  HashMap效率最高,LinkedList最低,HashXXX和TreeXXX效率都比较高,而基于List类效率耗时是Map或Set的十倍左右。

  (2)多线程模式下性能测试 ,测试元素100~1000,线程数10个中平均成绩 :

       添加 HashSet效率最高,LinkedList最低,HashXXX和TreeXXX效率都比较高,这里ArrayList效率较低,整体相差不大。

       删除 HashSet效率最高,LinkedList最低,整体性能同添加相似,但HashXXX或TreeXXX性能比List系列高出3倍。

       查找 HashSet性能最好,LinkedList最低,性能较差的是ArrayList,其他的均表现很好。

(3)其他

      对于随机访问的get和set,arraylist优于LinkedList,因为后者要移动指针;

      对于要新增和删除的操作,linkedList比较占优势,因为arraylist要移动数据(在尾部新增和删除除外)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值