《Java后端知识体系》系列之Java集合

为了几个月后的面试准备的汤姆!

先上集合知识图谱:有不足的或者错误的地方欢迎下方评论指正!

在这里插入图片描述
集合

  • Collection

    • List
      • ArrayList:
        • 底层实现:底层是可变数组的数据结构,默认的初始化长度为10,如果没有设置容量默认是空数组,然后在进行add的时候会扩容到10(此时是创建了一个新的数组,然后将旧的数组复制到新数组中),后面扩容的话是按照0.5倍的大小进行扩容的,是线程不安全的,底层是数组所以查询效率更高,新增、删除效率低。
      • LinkedList
        • 底层实现:底层是双向链表,地址是任意的,采用的是尾插法的的方式,在链表中有头节点、尾节点、指针,所以在插入和删除时不需要移动数据,所以效率高,但是查询时需要通过指针来寻找数据,所以效率很低;也是线程不安全的。
      • Vector
        • 底层实现:底层也是数组实现的,结构跟ArrayList差不多,但是Vector是线程安全的,底层通过使用synchronized锁维持线程安全,所以性能较低;Vector扩容时会扩容一倍(也就是扩容到当前容量的两倍),同时在扩容时可以通过设置增长因子来设定扩容。
    • Set
      • HashSet
        • 底层实现:HashSet是通过哈希表实现的,HashSet中的数据是无序的,可以存入null值,但是只能存入一个null,两个数据中的值不允许重复,就如数据库中的唯一约束;同时HashSet放入的对象必须实现hashcode方法,放入的对象都是以hashcode码作为唯一标识的。
      • TreeSet
        • 底层实现:TreeSet是通过红黑树实现的(底层继承了TreeMap,TreeMap是通过红黑树来实现的),在TreeSet中存储的是排好序的数据同时不允许有重复值,也是非线程安全的,效率上不如HashSet(二叉树要进行旋转消耗性能)
  • Map

    • TreeMap
      • 实现原理:TreeMap是通过红黑树来实现的(了解红黑树可以看这篇),红黑树是排好序的数据结构,是非线程安全的。
    • HashMap
      • 实现原理:HashMap的实现是通过数组+链表+红黑树(jdk1.8)非线程安全的,key可以为null值,默认的负载因子为0.75,在扩容时都是2的次幂(这是因为扩大2的次幂的容量后,重新计算数据的hash值的时候只会影响最高位的数据,这样就减少了重新分配位置的操作,提高了效率。可以看我这篇对源码的分析)。HashMap中当链表的长度大于等于8的时候(同时数组长度大于64不然只会进行扩容)会将链表转换为红黑树,同时当红黑树的长度小于6时,又会将红黑树转换为链表,在jdk1.8中采用了尾插法,这样的做法解决了jdk1.7中头插法的死循环问题.
    • HashTable
      • 实现原理:HashTable的实现原理跟HashMap类似,主要的区别在于HashTable是线程安全的,内部使用synchronized锁实现线程安全,因为使用synchronized所以性能比较差。
    • ConcurrentHashMap
      • 实现原理:ConcurrentHashMap是属于JUC并发包的一种,属于线程安全的结构,底层也是通过数组+链表+红黑树来实现的(jdk1.8),在ConcurrentHashMap的put方法中会根据hash值计算这个新插入的点在table中的位置i,如果位置i是空的,直接放进去,否则进行判断,如果i位置是树节点,按照树的方式插入新的节点,否则把i插入到链表的末尾,同时不允许key或value为null。对于多线程下的put存在两种情况:
        • 如果一个或多个线程正在对ConcurrentHashMap进行扩容操作,当前线程也要进入扩容的操作中。这个扩容的操作之所以能被检测到,是因为transfer方法中在空结点上插入forward节点,如果检测到需要插入的位置被forward节点占有,就帮助进行扩容(在扩容时多线程会帮助进行扩容以及数据的迁移)。
        • 如果检测到要插入的节点是非空且不是forward节点,就对这个节点加锁,这样就保证了线程安全。尽管这个有一些影响效率,但是还是会比hashTable的synchronized要好得多。

搞了两个小时知识总结,我真是会敲代码的汤姆猫!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章