Arrays.asList的缺陷

  • 避免使用基本数据类型数组转换为列表
    • list中是数组而不是将数组元素转化为list集合
  • asList产生的列表不可做写操作

subList的缺陷

  • subList返回仅仅只是一个视图,对子列表的操作会影响原列表

说说 List,Set,Map 三者的区别?

  • List (对付顺序的好帮⼿): 存储的元素是有序的、可重复的。
  • Set (注重独⼀⽆⼆的性质): 存储的元素是⽆序的、不可重复的。
  • Map (⽤ Key 来搜索的专家): 使⽤键值对(kye-value)存储,类似于数学上的函数 y=f(x),“x”代表key,”y”代表 value,Key 是⽆序的、不可重复的,value 是⽆序的、可重复的,每个键最多映射到⼀个值。

各集合的底层结构

  • List
    • Arraylist : Object[] 数组
    • Vector : Object[] 数组
    • LinkedList : 双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环)
  • Set
    • HashSet (⽆序,唯⼀): 基于 HashMap 实现的,底层采⽤ HashMap 来保存元素
    • LinkedHashSet : LinkedHashSet 是 HashSet 的⼦类,并且其内部是通过LinkedHashMap 来实现的。有点类似于我们之前说的
    • LinkedHashMap 其内部是基于HashMap 实现⼀样,不过还是有⼀点点区别的
    • TreeSet (有序,唯⼀): 红⿊树(⾃平衡的排序⼆叉树)
  • Map
    • HashMap : JDK1.8 之前 HashMap 由数组+链表组成的,数组是 HashMap 的主体,链表则是主

要为了解决哈希冲突⽽存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较⼤
的变化,当链表⻓度⼤于阈值(默认为 8)(将链表转换成红⿊树前会判断,如果当前数组的⻓
度⼩于 64,那么会选择先进⾏数组扩容,⽽不是转换为红⿊树)时,将链表转化为红⿊树,以
减少搜索时间

  • LinkedHashMap : LinkedHashMap 继承⾃ HashMap ,所以它的底层仍然是基于拉链式散

列结构即由数组和链表或红⿊树组成。另外, LinkedHashMap 在上⾯结构的基础上,增加了
⼀条双向链表,使得上⾯的结构可以保持键值对的插⼊顺序。同时通过对链表进⾏相应的操作,
实现了访问顺序相关逻辑。详细可以查看:《LinkedHashMap 源码详细分析(JDK1.8)》

  • Hashtable : 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突

⽽存在的

  • TreeMap : 红⿊树(⾃平衡的排序⼆叉树)

如何选⽤集合?

  • 主要根据集合的特点来选⽤,⽐如我们需要根据键值获取到元素值时就选⽤ Map 接⼝下的集合,需

要排序时选择 TreeMap ,不需要排序时就选择 HashMap ,需要保证线程安全就选⽤
ConcurrentHashMap 。

  • 当我们只需要存放元素值时,就选择实现 Collection 接⼝的集合,需要保证元素唯⼀时选择实现

Set 接⼝的集合⽐如 TreeSet 或 HashSet ,不需要就选择实现 List 接⼝的⽐如 ArrayList
或 LinkedList ,然后再根据实现这些接⼝的集合的特点来选⽤。

HashMap 和 Hashtable 的区别

  • 线程是否安全: HashMap 是⾮线程安全的,HashTable 是线程安全的,因为 HashTable 内部的

⽅法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使⽤ConcurrentHashMap 吧!)

  • 初始容量⼤⼩和每次扩充容量⼤⼩的不同 : ① 创建时如果不指定容量初始值,Hashtable 默认的初始⼤⼩为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化⼤⼩为16。之后每次扩充,容量变为原来的 2 倍。② 创建时如果给定了容量初始值,那么 Hashtable会直接使⽤你给定的⼤⼩,⽽ HashMap 会将其扩充为 2 的幂次⽅⼤⼩(HashMap 中的tableSizeFor() ⽅法保证,下⾯给出了源代码)。也就是说 HashMap 总是使⽤ 2 的幂作为哈希表的⼤⼩,后⾯会介绍到为什么是 2 的幂次⽅。

HashMap 和 HashSet 区别

  • HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码⾮常⾮常少,因为除了 clone() 、 writeObject() 、 readObject() 是 HashSet ⾃⼰不得不实现之外,其他⽅法都是直接调⽤ HashMap 中的⽅法。

HashMap 和 TreeMap 区搜索别

  • TreeMap 和 HashMap 都继承⾃ AbstractMap ,但是需要注意的是 TreeMap 它还实现了NavigableMap 接⼝(搜索)和 SortedMap 接⼝(排序)。

HashMap 的⻓度为什么是 2 的幂次⽅

  • hash%length == hash&(length-1)的前提是 length 是 2的 n 次⽅

HashMap 多线程操作导致死循环问题

  • 主要原因在于并发下的 Rehash 会造成元素之间会形成⼀个循环链表
  • jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使⽤ HashMap,因为多线程下使⽤ HashMap 还是会存在其他问题⽐如数据丢失。并发环境下推荐使⽤ ConcurrentHashMap 。

ConcurrentHashMap 和 Hashtable 的区别

  • 在 JDK1.7 的时候,ConcurrentHashMap(分段锁)
  • JDK1.8 ⽤ Node 数组+链表+红⿊树的数据结构来实现,并发控制使⽤synchronized 和 CAS 来操作, synchronized 只锁定当前链表或红⿊⼆叉树的⾸节点,这样只要 hash 不冲突,就不会产⽣并发,效率⼜提升 N 倍。

HashMap是头插法还是尾插法

  • JDK8以前是头插法,JDK8后是尾插法