Java 集合框架的基础接口有哪些?
- Collection ,为集合层级的根接口。一个集合代表一组对象,这些对象即为它的元素。Java 平台不提供这个接口任何直接的实现。
- Set ,是一个不能包含重复元素的集合。这个接口对数学集合抽象进行建模,被用来代表集合,就如一副牌。
- List ,是一个有序集合,可以包含重复元素。你可以通过它的索引来访问任何元素。List 更像长度动态变换的数组。
- Map ,是一个将 key 映射到 value 的对象。一个 Map 不能包含重复的 key,每个 key 最多只能映射一个 value 。
- 一些其它的接口有 Queue、Dequeue、SortedSet、SortedMap 和 ListIterator 。
为何 Collection 不从 Cloneable 和 Serializable 接口继承?
因为 Collection 是一个抽象表现,重要的是实现。如何维护这些元素由 Collection 的具体实现决定。例如,一些如 List 的 Collection 实现允许重复的元素,而其它的如 Set 就不允许。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。
为何 Map 接口不继承 Collection 接口?
尽管 Map 接口和它的实现也是集合框架的一部分,但 Map 不是集合,集合也不是 Map。Map 包含 key-value 对,它提供抽取 key 或 value 列表集合( Collection )的方法,但是它不适合“一组对象”规范。
Collection 和 Collections 的区别?
- Collection ,是集合类的上级接口,继承与他的接口主要有 Set 和List 。
- Collections ,是针对集合类的一个工具类,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
集合框架里实现的通用算法有哪些?
Java 集合框架提供常用的算法实现,比如排序和搜索。
Collections类包含这些方法实现。大部分算法是操作 List 的,但一部分对所有类型的集合都是可用的。部分算法有排序、搜索、混编、最大最小值。
集合框架底层数据结构总结
1)List
- ArrayList :Object 数组。
- Vector :Object 数组。
- LinkedList :双向链表(JDK6 之前为循环链表,JDK7 取消了循环)。
2)Map
- HashMap :
- JDK8 之前,HashMap 由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。
- JDK8 以后,在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8 )时,将链表转化为红黑树,以减少搜索时间。
- LinkedHashMap :LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看:《LinkedHashMap 源码详细分析(JDK1.8)》 。
- Hashtable :数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。
- TreeMap :红黑树(自平衡的排序二叉树)。
3)Set
- HashSet :无序,唯一,基于 HashMap 实现的,底层采用 HashMap 来保存元素。
- LinkedHashSet :LinkedHashSet 继承自 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的。
- TreeSet :有序,唯一,红黑树(自平衡的排序二叉树)。
什么是迭代器(Iterator)?
Iterator 接口,提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器实例的迭代方法。
Iterator 和 ListIterator 的区别是什么?
- Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
- Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
- ListIterator 实现了 Iterator 接口,并包含其他的功能。比如:增加元素,替换元素,获取前一个和后一个元素的索引等等。
为何 Iterator 接口没有具体的实现?
Iterator 接口,定义了遍历集合的方法,但它的实现则是集合实现类的责任。每个能够返回用于遍历的 Iterator 的集合类都有它自己的 Iterator 实现内部类。
这就允许集合类去选择迭代器是 fail-fast 还是 fail-safe 的。比如,ArrayList 迭代器是 fail-fast 的,而 CopyOnWriteArrayList 迭代器是 fail-safe 的。
Comparable 和 Comparator 的区别?
- Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”;假设存在实现了 Comparable接口的类的对象的List列表(或数组),则该List列表(或数组)可以通过Collections.sort(或Arrays.sort)进行排序。
- Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。若一个类实现了Comparator接口,则它一定要实现compare(T o1,T o2)方法。
ArrayList 集合加入 1 万条数据,应该怎么提高效率?
ArrayList 的默认初始容量为 10 ,要插入大量数据的时候需要不断扩容,而扩容是非常影响性能的。因此,现在明确了 10 万条数据了,我们可以直接在初始化的时候就设置 ArrayList 的容量!
ArrayList 是如何扩容的?
如果通过无参构造的话,初始数组容量为 0 ,当真正对数组进行添加时,才真正分配容量。每次按照 1.5 倍(位运算)的比率通过 copeOf 的方式扩容。
HashMap 的工作原理是什么?
HashMap 和 ConcurrentHashMap 的区别?
ConcurrentHashMap 是线程安全的 HashMap 的实现。主要区别如下:
-
1、ConcurrentHashMap 对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用 lock 锁进行保护,相对 于Hashtable 的 syn 关键字锁的粒度更精细了一些,并发性能更好。而 HashMap 没有锁机制,不是线程安全的。
JDK8 之后,ConcurrentHashMap 启用了一种全新的方式实现,利用 CAS 算法。
-
2、HashMap 的键值对允许有
null
,但是 ConCurrentHashMap 都不允许。
HashMap原理
https://aggtech.blog.youkuaiyun.com/article/details/119109031
HashSet 的工作原理是什么
HashSet 是构建在 HashMap 之上的 Set hashing 实现类。
// HashSet.java
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
-
map
属性,当我们创建一个 HashMap 对象时,其内部也会创建一个map
对象。后续 HashSet 所有的操作,实际都是基于这个map
之上的封装。 -
PRESENT
静态属性,所有map
中 KEY 对应的值,都是它,避免重复创建。
// HashSet.java
public boolean add(E e) {
return map.put(e, PRESENT) == null;
}
HashSet 如何检查重复
当你把对象加入 HashSet 时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较。
- 如果没有相符的 hashcode ,HashSet会假设对象没有重复出现。
- 但是如果发现有相同 hashcode 值的对象,这时会调用 equals 方法来检查 hashcode 相等的对象是否真的相同。
- 如果两者相同,HashSet 就不会让加入操作成功。
- 如果两者不同,HashSet 就会让加入操作成功。