简述 Java 的 List

List 是一个有序队列,在 Java 中有两种实现方式:ArrayList 使用数组实现,是容量可变的非线程安全列表,随机访问快,集合扩容时会创建更大的数组,把原有数组复制到新数组。LinkedList 本质是双向链表,与 ArrayList 相比插入和删除速度更快,但随机访问元素很慢。

Java 中线程安全的基本数据结构有哪些

HashTable: 哈希表的线程安全版,效率低ConcurrentHashMap:哈希表的线程安全版,效率高,用于替代 HashTable
Vector:线程安全版 Arraylist
Stack:线程安全版栈Blocking
Queue 及其子类:线程安全版队列

简述 Java 的 Set

Set 即集合,该数据结构不允许元素重复且无序。Java 对 Set 有三种实现方式:
HashSet 通过 HashMap 实现,HashMap 的 Key 即 HashSet 存储的元素,Value 系统自定义一个名为 PRESENT 的 Object 类型常量。判断元素是否相同时,先比较 hashCode,相同后再利用 equals 比较,查询 O(1)LinkedHashSet 继承自 HashSet,通过 LinkedHashMap 实现,使用双向链表维护元素插入顺序。
TreeSet 通过 TreeMap 实现的,底层数据结构是红黑树,添加元素到集合时按照比较规则将其插入合适的位置,保证插入后的集合仍然有序。查询 O(logn)

简述 Java 的 HashMap

JDK8 之前底层实现是数组 + 链表,JDK8 改为数组 + 链表/红黑树。主要成员变量包括存储数据的 table 数组、元素数量 size、加载因loadFactor。HashMap 中数据以键值对的形式存在,键对应的 hash 值用来计算数组下标,如果两个元素 key 的 hash 值一样,就会发生哈希冲突,被放到同一个链表上。table 数组记录 HashMap 的数据,每个下标对应一条链表,所有哈希冲突的数据都会被存放到同一条链表,Node/Entry 节点包含四个成员变量:key、value、next 指针和 hash 值。
在 JDK8 后链表超过 8 会转化为红黑树。若当前数据/总数据容量>负载因子,Hashmap 将执行扩容操作。默认初始化容量为 16,扩容容量必须是 2 的幂次方、最大容量为 1<< 30 、默认加载因子为 0.75。

为何 HashMap 线程不安全

在 JDK1.7 中,HashMap 采用头插法插入元素因此并发情况下会导致环形链表,产生死循环。虽然
JDK1.8 采用了尾插法解决了这个问题,但是并发下的 put 操作也会使前一个 key 被后一个 key 覆盖。由于 HashMap 有扩容机制存在,也存在 A 线程进行扩容后,B 线程执行 get 方法出现失误的情况。

简述 Java 的 TreeMap

TreeMap 是底层利用红黑树实现的 Map 结构,底层实现是一棵平衡的排序二叉树,由于红黑树的插入、删除、遍历时间复杂度都为 O(logN),所以性能上低于哈希表。但是哈希表无法提供键值对的有序输出,红黑树可以按照键的值的大小有序输出。

ArrayList、Vector 和 LinkedList 有什么共同点与区别?

ArrayList、Vector 和 LinkedList 都是可伸缩的数组,即可以动态改变长度的数组。
ArrayList 和 Vector 都是基于存储元素的 Object[] array 来实现的,它们会在内存中开辟一块连续的空间来存储,支持下标、索引访问。但在涉及插入元素时可能需要移动容器中的元素,插入效率较低。当存储元素超过容器的初始化容量大小,ArrayList 与 Vector 均会进行扩容。
Vector 是线程安全的,其大部分方法是直接或间接同步的。
ArrayList 不是线程安全的,其方法不具有同步性质。
LinkedList 也不是线程安全的。LinkedList 采用双向列表实现,对数据索引需要从头开始遍历,因此随机访问效率较低,但在插入元素的时候不需要对数据进行移动,插入效率较高。

HashMap 和 Hashtable 有什么区别?

HashMap 是 Hashtable 的轻量级实现,HashMap 允许 key 和 value 为 null,但最多允许一条记录的 key 为 null.而 HashTable 不允许。HashTable 中的方法是线程安全的,而 HashMap 不是。在多线程访问 HashMap 需要提供额外的同步机制。Hashtable 使用 Enumeration 进行遍历,HashMap 使用 Iterator 进行遍历。

如何决定使用 HashMap 还是 TreeMap?

如果对 Map 进行插入、删除或定位一个元素的操作更频繁,HashMap 是更好的选择。如果需要对 key 集合进行有序的遍历,TreeMap 是更好的选择。

HashSet 中,equals 与 hashCode 之间的关系?

equals 和 hashCode 这两个方法都是从 object 类中继承过来的,equals 主要用于判断对象的内存地址引用是否是同一个地址;hashCode 根据定义的哈希规则将对象的内存地址转换为一个哈希码。HashSet 中存储的元素是不能重复的,主要通过 hashCode 与 equals 两个方法来判断存储的对象是否相同:如果两个对象的 hashCode 值不同,说明两个对象不相同。如果两个对象的 hashCode 值相同,接着会调用对象的 equals 方法,如果 equlas 方法的返回结果为 true,那么说明两个对象相同,否则不相同。

fail-fast 和 fail-safe 迭代器的区别是什么?

fail-fast 直接在容器上进行,在遍历过程中,一旦发现容器中的数据被修改,就会立刻抛出 ConcurrentModificationException 异常从而导致遍历失败。常见的使用 fail-fast 方式的容器有 HashMap 和 ArrayList 等。
fail-safe 这种遍历基于容器的一个克隆。因此对容器中的内容修改不影响遍历。常见的使用 fail-safe 方式遍历的容器有 ConcurrentHashMap 和 CopyOnWriteArrayList。

Collection 和 Collections 有什么区别?

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如 List、Set 等。
Collections 是一个包装类,包含了很多静态方法、不能被实例化,而是作为工具类使用,比如提供的排序方法:Collections.sort(list);提供的反转方法:Collections.reverse(list)。