Java集合框架都有哪些?
实现Collection
接口的,存放特定元素的集合的对象
实现Map
接口的,将键映射到值的对象
集合框架底层数据结构总结
List
- ArrayList :Object 数组。
- Vector :Object 数组。
- LinkedList :双向链表(JDK6 之前为循环链表,JDK7 取消了循环)。
Set
- HashSet :无序,唯一,基于 HashMap 实现的,底层采用 HashMap 来保存元素。()
- LinkedHashSet :LinkedHashSet 继承自 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的。
- TreeSet :有序,唯一,红黑树(自平衡的排序二叉树)。
Map
- HashMap:HashMap 由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。
JDK8 以后,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8 )时,将链表转化为红黑树,以减少搜索时间。
- LinkedHashMap:LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
- Hashtable :数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。
- TreeMap :红黑树(自平衡的排序二叉树)。
List 和 Set 区别?
List,Set 都是继承自 Collection 接口。
- List 特点:元素有放入顺序,元素可重复。可以用下标遍历或者迭代器遍历。
- Set 特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉。只能用迭代器遍历。
ArrayList 与 LinkedList 区别?
ArrayList
- 优点:ArrayList 是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
- 缺点:因为地址连续,ArrayList 要移动数据,所以插入和删除操作效率比较低。
LinkedList
- 优点:LinkedList 基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址。对于新增和删除操作 add 和 remove ,LinedList 比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景。
- 缺点:因为 LinkedList 要移动指针,所以查询操作性能比较低。
适用场景分析:
- 当需要对数据进行对随机访问的情况下,选用 ArrayList 。
- 当需要对数据进行多次增加删除修改时,采用 LinkedList 。
ArrayList 是如何扩容的?
如果通过无参构造的话,初始数组容量为 0 ,当真正对数组进行添加时,才真正分配容量。每次按照 1.5 倍(位运算)的比率通过 copeOf 的方式扩容。
HashSet 和 TreeSet 的区别?
- HashSet底层用HashMap实现的
- TreeSet底层用TreeMap实现的
HashMap 和 TreeMap 的区别?
- HashMap底层实现是数组+链表或者红黑树,TreeMap底层实现是红黑树
- Map 中插入、删除和定位元素这类操作,HashMap 比较适合
- 假如你需要对一个有序的 key 集合进行遍历, TreeMap 更适合。
HashMap 和 ConcurrentHashMap 的区别?
ConcurrentHashMap 是线程安全的 HashMap 的实现。
HashMap原理
我们知道在 Java 中最常用的两种结构是数组和模拟指针(引用),几乎所有的数据结构都可以利用这两种来组合实现,HashMap 也是如此。实际上 HashMap 是一个链表散列。
HashMap 是基于 hashing 的原理。
HashMap 的长度为什么是 2 的幂次方?
为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。
这个算法应该如何设计呢?我们首先可能会想到采用 % 取余的操作来实现。但是,重点来了:
- 取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作(也就是说
hash % length == hash & (length - 1)
的前提是 length 是 2 的 n 次方;)。 - 并且,采用二进制位操作 &,相对于 % 能够提高运算效率,
这就解释了 HashMap 的长度为什么是 2 的幂次方。
什么是迭代器(Iterator)?
Iterator 接口,提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素,但是不可以直接调用集合的 #remove(Object Obj)
方法删除,可以通过迭代器的 #remove()
方法删除。
Iterator 和 ListIterator 的区别是什么?
- Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
- Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
- ListIterator 实现了 Iterator 接口,并包含其他的功能。比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。
快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
差别在于 ConcurrentModification 异常:
- 快速失败:当你在迭代一个集合的时候,如果有另一个线程正在修改你正在访问的那个集合时,就会抛出一个 ConcurrentModification 异常。 在
java.util
包下的都是快速失败。 - 安全失败:你在迭代的时候会去底层集合做一个拷贝,所以你在修改上层集合的时候是不会受影响的,不会抛出
ConcurrentModification
异常。在java.util.concurrent
包下的全是安全失败的。
如何删除 List 中的某个元素?
有两种方式,分别如下:
- 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
- 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
Comparable 和 Comparator 的区别?
- Comparable 接口,
在 java.lang
包下,用于当前对象和其它对象的比较,所以它有一个#compareTo(Object obj)
方法用来排序,该方法只有一个参数。 - Comparator 接口,在
java.util
包下,用于传入的两个对象的比较,所以它有一个#compare(Object obj1, Object obj2)
方法用来排序,该方法有两个参数。