一、集合框架概述
1.1 Collection
1.2 Map
1.3 集合框架底层数据结构总结
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 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
- Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
- TreeMap: 红黑树(自平衡的排序二叉树)
二、常见面试题目
2.1 ArrayList、Vector和LinkedList的特点
- ArrayList 和 Vector 都是基于数组实现的,它们会在内存中开辟一块连续的空间来存储,因此都支持快速随机访问。对于插入和删除元素的时间复杂度受元素位置的影响。在列表末尾添加或者删除元素时,时间复杂度为O(1);如果要在指定位置 i 插入和删除元素的话时间复杂度就为 O(n-i)。
- ArrayList 和 Vector 都采用动态扩容方式进行扩容列表,ArrayList 默认扩容为原来的1.5倍,Vector 默认扩容为原来的2倍。
- LinkedList 底层基于双向列表实现,即采用链表存储,所以对于add(E e)方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置 i 插入和删除元素的话时间复杂度近似为 O(n) ,因为需要先移动到指定位置再插入。
- ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;Vector 大多数方法都是直接或间接同步的,因此是线程安全的。
2.2 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
- HashSet 是 Set 接口的主要实现类 ,HashSet 的底层是 HashMap,线程不安全的,可以存储 null 值;
- LinkedHashSet 是 HashSet 的子类,能够按照添加的顺序遍历;
- TreeSet 底层使用红黑树,能够按照添加元素的顺序进行遍历,排序的方式有自然排序和定制排序。
2.3 HashMap 和 Hashtable 的区别
- 1、线程是否安全: HashMap 是非线程安全的,HashTable 是线程安全的。
- 2、效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。
- 3、对 Null key 和 Null value 的支持: HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个,null 作为值可以有多个;HashTable 不允许有 null 键和 null 值,否则会抛出 NullPointerException。
- 4、初始容量大小和每次扩充容量大小的不同 :
- ① 创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11,之后每次扩充,容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充,容量变为原来的 2 倍。
- ② 创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小(为了适应底层数据结构的实现)。
- 5、底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
2.4 HashMap 和 TreeMap 区别
- TreeMap 和HashMap 都继承自AbstractMap ,但是需要注意的是TreeMap它还实现了NavigableMap接口和SortedMap 接口。
- 实现 NavigableMap 接口让 TreeMap 有了对集合内元素的搜索的能力。
- 实现SortMap接口让 TreeMap 有了对集合中的元素根据键排序的能力。默认是按 key 的升序排序,不过我们也可以指定排序的比较器。
- 综上,相比于HashMap来说 TreeMap 主要多了对集合中的元素根据键排序的能力以及对集合内元素的搜索的能力。
2.5 HashSet 如何检查重复
当你把对象加入HashSet时,HashSet 会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让加入操作成功。