java集合(一)常见问题
-
- 0. java集合框架
- 1. 说说List,Set,Map三者的区别?
- 2. Arraylist 与 LinkedList 区别?
- 3.ArrayList 与 Vector 区别呢?为什么要⽤Arraylist取代Vector呢?
- 4. HashMap 和 Hashtable 的区别
- 5. HashMap 的长度为什么是2的幂次方
- 6. HashMap 和 HashSet区别
- 7. HashSet是如何检查重复的?
- 8. HashMap的底层实现
- 9. ConcurrentHashMap 和 Hashtable 的区别
- 10. 集合和数组的区别
- 11.常用的集合底层的数据结构?
- 12. Java集合的快速失败机制 “fail-fast”?
- 13.Iterator 怎么使用?有什么特点?
- 14.如何边遍历边移除 Collection 中的元素?
- 15. 遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么?
- 16.如何实现数组和 List 之间的转换?
- 17.多线程场景下如何使用 ArrayList?
- 18.BlockingQueue是什么?
- 19.在 Queue 中 poll()和 remove()有什么区别?
- 20.详解HashMap的实现原理?
0. java集合框架
Java集合主要有4个部分:List列表、Set集合、Map映射、工具类(Iterator迭代器、Enumeration枚举类、Arrays和Collections)。每一个容器(集合类)能盛不同的液体(数据)。所以容器的功能不同使用场景不同。
java集合类框架如下所示:
先抓住它的主干,即Iterator、Collection和Map。(虚框线是接口,实框线是类)
-
Collection包含了集合的基本操作和属性的高度抽象的接口。 Collection包含了List和Set两大分支。
(1) List是一个有序的队列,实现类有4个:LinkedList, ArrayList, Vector, Stack。
(2) Set是一个不允许有重复元素的集合。实现类有3个:TreeSet、HashSet、LinkHahtSet。 -
Map一个映射接口,即key-value键值对。
(1)AbstractMap是个抽象类,它实现了Map接口中的大部分API。实现类有6个:TreeMap、HashMap、LinkHashMap、IdentityHashMap、WeakHashMap、HashTable
(2)SortedMap 是继承于Map的接口。内容是排序的键值对,通过比较器(Comparator) -
Iterator。它是遍历集合的工具,即我们通常通过Iterator迭代器来遍历集合。
1. 说说List,Set,Map三者的区别?
- List以特定索引来存取元素,可以有重复元素。
- Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)。
- Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一。
- Set和Map容器都有基于哈希存储(HashSet/HashMap)和排序树(TreeSet/TreeMap)的两种实现版本,基于哈希存储的版本理论存取时间复杂度为O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的键(key)构成排序树从而达到排序和去重的效果。
2. Arraylist 与 LinkedList 区别?
-
是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
-
底层数据结构: Arraylist 底层使用的是 Object 数组;LinkedList 底层使用的是 双向链表 数据结构
-
插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似O(1)而数组为近似O(n)。
-
是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
-
内存空间占用: ArrayList的空间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
数据结构基础之双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表,如下图所示,同时下图也是LinkedList 底层使用的是双向循环链表数据结构。
3.ArrayList 与 Vector 区别呢?为什么要⽤Arraylist取代Vector呢?
这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合
(1)线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
(2)性能:ArrayList 在性能方面要优于 Vector。
(3)扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。
4. HashMap 和 Hashtable 的区别
-
线程是否安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);
-
效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;
-
对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。
-
初始容量大小和每次扩充容量大小的不同 : ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。
-
底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
hashmap中初始容量的构造方法:
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.