关于集合(每日笔记)

关于集合(每日笔记)

什么是集合?

集合是作为数据结构的载体,可以对元素景象加工和输出,以一定的算法实现最基本的增删改查功能因此集合是所有编程语言的基础

数组(了解)

数组可以使用索引下标进行快速定位,并获取指定位置的元素

数组的下标是从0开始的,这源于BCPL语言,它将指针设置在0位置,用数组下标作为直接偏移量进行计算

如果下标从1开始,计算机偏移量就要使用当前下标减1的操作.加减法运算在数组下标使用频率极高的场景下,这种运算十分耗时。

集合的体系结构

第一类:

按照单个元素存储的Collection,在继承树中List接口与Set接口都实现了Collection接口

  • Collection
    • List
      • ArrayList
      • LinkedList
      • Vector(了解)
    • Set
      • HashSet
      • TreeSet
      • LinkedHashSet
    • Queue(了解)
      • LinkedBlockingQueue(了解)

第二类

按照Key-Value存储的Map(键值对)

  • Map
    • HashMap
    • TreeMap
    • ConcurrentHashMap
    • HashTable
    • LinkedHashMap

List

List集合是线性数据结构的主要实现,集合元素通常存在明确的上一个和下一个元素,也存在明确的第一个元素和最后一个元素。

特点:

​ 有序、可重复、可通过索引值操作元素

ArrayList

  • 底层是数组,查询快,增删慢。
  • ArrayList是容量可以改变的非线程安全集合。内部实现使用数组进行存储,集合扩容时会创建更大的数组空间,把原有数据复制到新数组中。
  • ArrayList支持对元素的快速随机访问,但是插入与删除时速度通常很慢,因为这个过程很可能需要移动其它元素。

LinkedList

  • 底层是链表,查询慢,增删快。
  • LinkedList本质是双向链表。与ArrayList相比,LinkedList的插入和删除速度更快,但是随机访问速度则很慢。

Set

特点:

特点:无序、元素唯一

HashSet

  • HashSet从源码分析是使用HashMap来实现的,只是value固定为一个静态对象,使用key保证集合元素的唯一性,但它不保证集合元素的顺序。

TreeSet

  • TreeSet从源码分析是使用TreeMap来实现的,底层为树结构,在添加新元素到集合中时,按照某种比较规则将其插入合适的位置,保证插入后的集合仍然是有序的。

  • Integer和String对象都可以进行默认的TreeSet排序,而自定义类的对象是不可以的,自己定义的类必须实现Comparable接口或者定义外部比较器Comparator,才可以正常使用。

  • LinkedHashSet

    • LinkedHashSet继承自HashSet,内部使用链表维护了元素插入顺序。

Map

Map集合是以Key-Value键值对作为存储元素实现的哈希结构,Key按哈希函数计算后是唯一的,Value则是可以重复的。Key、Value是否允许为null,以实现类约束为准。
Hashtable因为性能瓶颈已经被淘汰;广泛使用的HashMap线程是不安全的;ConcurrentHashMap是线程安全的,在JDK8中进行了锁的大幅度优化;TreeMap是Key有序的Map类集合。
在多线程并发场景中,优先推荐使用ConcurrentHashMap,而不是HashMap。

Hashtable

  • Key不允许为null,Value不允许为null。
  • 早期Java类库提供的哈希表的实现。
  • 线程安全:涉及到修改Hashtable的方法,使用Synchronized修饰。
  • 串行化的方式运行,性能较差。

TreeMap

  • Key不允许为null,Value允许为null。
  • TreeMap是按照Key的排序结果来组织内部结构的Map类集合,它改变了Map类散乱无序的形象。
  • TreeMap的插入操作就是按Key的对比往下遍历,大于比较节点值的向右走,小于比较节点值的向左走,先按照二叉查找树的特性进行操作,后续会重新着色和旋转,保持红黑树的特性。
  • TreeMap是线程不安全的集合,不能在多线程之间进行共享数据的写操作。在多线程进行写操作时,需要添加互斥机制,或者把对象放在Collections.synchronizedMap(treeMap)中实现同步。

HashMap

  • Key允许为null,Value允许为null。
  • Java8以前底层数据结构:数组+链表。查询性能恶化:从O(1)变成O(N)。
  • Java8及以后底层数据结构:数组+链表+红黑树。最坏情况下性能从O(N)提高到O(logN)。默认情况下链表长度超过8变成红黑树,红黑树节点树小于6变回链表。
  • Java8HashMap的put()方法的逻辑:
    • 如果HashMap未被初始化过,则初始化。
    • 对Key求Hash值,然后再计算下标
    • 如果没有碰撞,直接放入桶中
    • 如果碰撞了,以链表的方式链接到后面。
    • 如果链表长度超过阀值,就把链表转成红黑树。
    • 如果链表长度低于6,就把红黑树转回链表。
    • 如果节点以及存在就替换旧值。
    • 如果桶满了(容量16*加载因子0.75),就需要resize(扩容2倍后重排)。

ConcurrentHashMap

  • Key不允许为null,Value不允许为null。
  • 早期的ConcurrentHashMap通过分段锁Segment来实现。
    • Segment 通过继承 ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
  • (Java8)ConcurrentHashMap:CAS+synchronized使锁更细化。
    • 首先使用无锁操作CAS插入头节点,失败则循环重试。若头节点已存在,则尝试获取头节点的同步锁,再进行操作。

在Java8中,HashMap、Hashtable、ConcurrentHashMap的区别

* HashMap线程不安全,数组+链表+红黑树
* Hashtable线程安全,锁住整个对象,数组+链表
* ConcurrentHashMap线程安全,CAS+同步锁,数组+链表+红黑树
* HashMap的key、value均可以为null,而其它的两个类不支持。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章