Java JDK1.8(十) - Set集合与集合分析完成总结

Set集合总结

      HashSet是通过HashMap实现。

      LinkedHashSet是通过LinkedHashSet实现。

      TreeSet在一定程度上来说,是通过TreeMap实现的。

      HashSet、LinkedHashSet、TreeSet都是没有自己的数据结构和非线程安全的,都是具备有Fail-Fast机制,并且相对来说特性都是和对应的底层实现Map方法是一样。

      在之前讲的TreeMap源码中,提到put方法是不能有null值的,那么自然的TreeSet也是不允许有null值的。

      HashSet、LinkedHashSet、TreeSet源码中都没有get()方法,说明只能通过迭代器来进行查找元素,无法像数组那样直接随机查找。

      TreeSet和LinkedHashSet都是有序的,但是LinkedHashSet没有实现SortedSet接口,LinkedHashSet的有序性是依赖于LinkedhashMap的有序性,所以它的有序性是只保证插入顺序的有序性。而TreeSet实现了SortedSet接口,有序性是依赖NavigableMap的有序性,而NavigableMap继承于SortedMap,这个接口的有序性是按照key的自然排序保证的有序性,而key的自然排序可以通过Comparable或Comparator比较器实现。

集合总结

      1、ArrayList是使用数组存储的,LinkedList使用双向链表存储的,两者都允许存储null,也允许存储重复的值。

在性能上ArrayList在存储大量元素时的增删效率低于LinkedList,因为ArrayList在增删是需要拷贝元素到新的数组,而LinkedList只需要将元素前后指针改变。

在根据角标获取元素的效率上ArryList由于LinkedList,以数组本身就是连续存储,支持随机访问,而LinkedList存储的元素是离散的,需要遍历链表;两者都是非线程安全的。

      2、ArrayList的扩容机制由于Vector,ArrayList每次resize增加1.5倍的容量,Vector每次增加2倍的容量,在存储大量元素后扩容会出现很大的空间浪费。

Vector增删方法和迭代都是synchronized修饰的,在线程安全的情况下使用效率低于ArrayList。

      3、JDK1.7中HashMap底层用数组+单链表的存储结构,JDK1.8后HashMap底层用数组+单链表/红黑树,在同一hash桶中节点数量,超过8的话,链表就会转换为红黑树。

      JDK1.7中函数使用4次位运算+5次异或运算,JDK1.8中降到1次位运算 + 1次异或预算。

      HashMap扩容的时候会增加到原来数组长度2倍,并对所存储的元素节点hash值的重新计算。

JDK1.7中HashMap会重新调用hash函数计算新的位置,而JDK1.8中对此进行了优化通过(e.hash & oldCap) == 0来确定节点新位置是位于扩容前的角标还是之前的2倍角标位置。

4、HashMap是非线程安全的,Hashtable是线程安全的,HashMap允许K-V为null,Hashtable不小允许K-V为null。

HashMap默认容量是2^4,且容量一定是2^n,Hashtable默认容量是11,不一定是2^n。

5、LinkedHashMap有与类似HashMap的底层hash表结构,但LinkedHashMap是使用数组+双链表/红黑树,也拥有相同的扩容机制。

HashMap元素的顺序不一定与元素的插入顺序相同,而LinkedHashMap则通过遍历双向链表来获取元素,所以遍历顺序在一定条件下等于插入顺序。

      LinkedHashMap可以通过构造参数accessOrder来指定双向链表是否在元素被访问后改变其在双向链表中的位置。

      6、HashSet内部使用HashMap存储元素,对应的键值对的键为Set的存储元素,值为一个默认的Object对象。

      HashSet通过存储元素的HashCode方法和equals方法来确定元素是否重复。

      7、Fail-Fast快速失败机制,是指在用迭代器迭代集合时,不允许集合中的对象发生增删改操作,否则会抛出ConcurrentModificationException,内部原理就是在next()方法检查modCount值是否有变化。

在java.util包下的集合类几乎都是具备有Fail-Fast机制。

在使用for/foreach循环迭代元素过程中不允许调用remove()方法删除元素,否则会导致ConcurrentModificationException异常。

Iterator可以删除访问的当前元素,一旦删除的元素是Iterator对象中next()所在引用的,在Iterator删除元素通过修改modCount与expectedModCount的值,可以在下次调用remove方法时,两者仍然相同,因此不会抛出ConcurrentModificationException。

8、Set集合都是没有get()方法,都是通过迭代器来查找元素的,并Set的集合底层基本都是使用对应的Map集合实现的。

发布了105 篇原创文章 · 获赞 34 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Su_Levi_Wei/article/details/105267075