Java集合框架

      Java集合框架包括很多集合类:

      List: ArrayList, LinkedList, Vector, Stack
      Set: HashSet, LinkedHashSet, TreeSet
      Queue: PriorityQueue, ArrayDeque
      Map: HashMap, LinkedHashMap, TreeMap, HashTable, WeakHashMap

      并发 
      List: CopyOnWriteArrayList
      Set: CopyOnWriteArraySet, ConCurrentSkipListSet
      Queue: ArrayBlockingQueue, LinkedBlockingQueue, DelayQueue, PriorityBlockingQueue, SynchronousQueue,             ConcurrentLinkedQueue
      Map: ConcurrentHashMap, ConcurrentSkipListMap

      Collections: synchronizedList, synchronizedMap, synchronizedSet, synchronizedSortedMap, synchronizedSortedSet,     synchronizedNavigableMap, synchronizedNavigableSet

      下面介绍各个类的具体内容。

①ArrayList

      底层实现:数组
      初始容量:10
      扩容:1.5倍。因为如果一次扩容太大,可能会浪费更多的内存,而如果一次性扩容太小,需要多次对数组重新分配内存,对性能消耗比较严重。
      modCount作用:在多线程操作过程中发现modCount不一致并抛出错误,即fail-fast机制。

      注意:数组存放的是元素的引用,而不是元素本身。

②LinkedList

      底层实现:双向链表

③Vector

      底层实现:数组
      初始容量:10
      扩容:2倍。可指定扩容增量。
      线程安全
      对于 Vector 整个的扩容过程,就是根据 capacityIncrement 确认扩容大小的,若 capacityIncrement <= 0 则扩大一倍,否则扩大至 capacityIncrement 。当然这个容量的最大范围为 Integer.MAX_VALUE即,2^32 – 1,所以 Vector 并不是可以无限扩充的。

④stack

      底层实现:继承Vector
      线程安全

⑤HashMap

      底层实现:数组+列表
      初始容量:16
      默认加载因子:0.75
      扩容:2倍
      线程不安全
      容量表示哈希表中桶的数量,初始容量是创建哈希表时的容量,加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度,它衡量的是一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。

      查找一个元素的平均时间是 O(1+a),因此如果负载因子越大,对空间的利用更充分,然而后果是查找效率的降低;如果负载因子太小,那么散列表的数据将过于稀疏,对空间造成严重浪费。

       HashMap 保存数据的过程为:当我们向一个 HashMap 中添加一对 key-value 时,系统首先会计算 key 的 hash 值,然后根据 hash 值确认在 table 中存储的位置。若该位置没有元素,则直接插入。否则迭代该处元素链表并依此比较其 key 的 hash 值。如果两个 hash 值相等且 key 值相等 (e.hash == hash && ((k = e.key) == key || key.equals(k))),则用新的 Entry 的 value 覆盖原来节点的 value。如果两个 hash 值相等但 key 值不等 ,则将该节点插入该链表的链头
       HashMap的初始容量总设为2的n次方, 是因为当 length = 2^n 时,不同的 hash 值发生碰撞的概率比较小,这样就会使得数据在 table 数组中分布较均匀,查询速度也较快。

       HashMap的数组table用了transient修饰,也就是说table里面的内容全都不会被序列化,因为HashMap是基于HashCode的,HashCode作为Object的方法,是native的,这意味着的是,HashCode和底层实现相关,不同的虚拟机可能有不同的HashCode算法,Java采取了重写自己序列化table的方法,在writeObject选择将key和value追加到序列化的文件最后面,而在readObject的时候重构HashMap数据结构。

⑥HashSet

      底层实现:基于HaspMap
      HashSet 中的所有元素都是保存在 HashMap 的 key 中,value 则是使用的 PRESENT 对象,该对象为 static final。

⑦HashTable

      底层实现:
      初始容量:11
      加载因子:0.75
      扩容:2倍+1
      线程安全
      put 方法的整个处理流程是:计算 key 的 hash 值,根据 hash 值获得 key 在 table 数组中的索引位置,然后迭代该 key 处的 Entry 链表(我们暂且理解为链表),若该链表中存在一个这个的 key 对象,那么就直接替换其 value 值即可,否则在将改 key-value 节点插入该 index 索引位置处。


HashMap和HashTable的区别:

      (1)HashMap是非线程安全的,Hashtable所有对外提供的方法都使用了synchronized,也就是同步,HashTable是线程安全的。
      (2)HashMap允许key和value可以为null,而HashTable不允许。
      (3)由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。
      (4)HashMap不能保证随着时间的推移Map中的元素次序是不变的。
      (5)HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。
      (6)容量和扩容大小都不一致。

⑧LinkedHashMap

      底层实现:散列表+双向链表
      非线程安全
    LinkedHashMap 是 HashMap 的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用 LinkedHashMap。

⑨CopyOnWriteArrayList

      顾名思义,Write的时候总是要Copy,也就是说对于CopyOnWriteArrayList,任何可变的操作(add、set、remove等等)都是伴随复制这个动作的。

      ·底层实现:数组
      ·是否允许为空:允许
      ·是否允许重复数据:允许
      ·是否有序:有序
      ·是否线程安全:线程安全

      一次add大致经历了几个步骤:
      1、加锁
      2、拿到原数组,得到新数组的大小(原数组大小+1),实例化出一个新的数组来
      3、把原数组的元素复制到新数组中去
      4、新数组最后一个位置设置为待添加的元素(因为新数组的大小是按照原数组大小+1来的)
      5、把Object array引用指向新数组
      6、解锁
     插入、删除、修改操作都是一样,每一次的操作都是以对Object[] array进行一次复制为基础的。CopyOnWriteArrayList的缺点,就是修改代价十分昂贵,每次修改都伴随着一次的数组复制。CopyOnWriteArrayList适用于读操作远多于修改操作的并发场景中。

⑩TeeMap

      增删改查log(n)
      统计性能long(n)
      非线程安全
      key不允许为空,value允许为空 
      key重复会覆盖,value允许重复

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值