1.数组与集合区别,用过哪些?

1.

  • 长度可变性: 数组是定长的,一旦创建无法扩容;集合(如 ArrayList)支持动态扩容,能自动适应数据增长。

  • 存储类型: 数组既可以存储基本数据类型(int, char),也可以存储引用对象;集合只能存储引用对象(基本类型会通过自动装箱处理)。

  • 功能丰富度: 数组功能单一,仅能通过索引访问;集合框架(JCF)提供了丰富的 API(如排序、搜索、去重、线程安全方案等),开发效率更高。

2.

我会按照 List、Set、Map 三大体系进行分类说明,这体现了你对体系结构的清晰认知:

  • List(有序、可重复):

    • ArrayList: 基于动态数组,随机访问快,是我在查询密集型场景的首选。

    • LinkedList: 基于双向链表,虽然随机访问慢,但在频繁头尾增删的场景下表现更好。

  • Set(无序、唯一):

    • HashSet: 基于 HashMap 实现,用于数据去重。

    • TreeSet: 基于红黑树,适用于需要对元素进行自然排序或自定义排序的场景。

  • Map(键值对存储):

    • HashMap: 性能最高,最常用的键值对存储容器。

    • ConcurrentHashMap: 线程安全且高效,在高并发场景下代替 Hashtable

    • LinkedHashMap: 维护了插入顺序,常用于实现 LRU 缓存。

3.Java中的线程安全的集合是什么?

集合分类代表容器实现机制 (核心原理)锁粒度适用场景
早期遗留Vector / Hashtable方法上直接加 synchronized全表锁 (锁整个对象)基本已被淘汰,不建议使用
工具包装Collections.synchronizedX内部维护 mutex 互斥对象全表锁 (对象级锁)并发量极小、对性能无要求的简单场景
现代并发 (Map)ConcurrentHashMapCAS + synchronized (Node 头节点)行级锁 (分段/桶锁)高并发 键值对读写存储 (推荐首选)
现代并发 (List)CopyOnWriteArrayList写时复制 (Copy-on-write)仅写操作加锁 (ReentrantLock)读多写少 (如白名单、配置缓存)
阻塞队列ArrayBlockingQueueReentrantLock + Condition队列对象锁生产者-消费者模型、线程池任务调度

4.Collections和Collection的区别

特性Collection (接口)Collections (工具类)
本质集合层次结构的根接口操作集合的静态工具类
包位置java.util.Collectionjava.util.Collections
主要用途定义了所有单列集合(List, Set)的核心标准方法(如 add, remove, size)。提供静态方法对集合进行搜索、排序、转换、线程安全化处理等。
继承关系ListSetQueue 继承。继承自 Object,不能被实例化(构造方法是私有的)。
你必须记住的 Collections 常用方法(面试常问):
  1. 排序: Collections.sort(list)

  2. 翻转: Collections.reverse(list)

  3. 查找: Collections.binarySearch(list, key)

  4. 线程安全包装: Collections.synchronizedList(list)

  5. 不可变集合: Collections.unmodifiableList(list)

5.集合遍历的方法有哪些?

以下是针对 Collection(List/Set)和 Map 两个体系的分类总结:

1. Collection 体系(List、Set)的遍历

  • 普通 for 循环

    • 特点:基于索引(index)访问。

    • 适用场景:仅适用于实现了 RandomAccess 接口的集合(如 ArrayList)。如果是 LinkedList,性能会极差($O(n^2)$)。

  • 增强 for 循环 (for-each)

    • 本质:Java 的语法糖,底层依赖 Iterator

    • 优点:代码简洁,可读性好。

    • 缺点:在遍历过程中不能直接修改集合结构(如 remove),否则会抛出 ConcurrentModificationException(fail-fast 机制)。

  • Iterator(迭代器)

  • 特点:最标准的遍历方式。

  • 核心优势唯一可以在遍历时安全删除元素的方法(需调用 iterator.remove())。

  • forEach + Lambda (Java 8+)

    • 特点:函数式编程风格,极其简洁。

    • 适用场景:仅需对每个元素执行简单操作时使用。

2. Map 体系的遍历(面试官最看重性能)

  • EntrySet 遍历(最推荐)

    for (Map.Entry<K, V> entry : map.entrySet()) { ... }
    • 性能最高:一次性取出 Key 和 Value。
  • KeySet 遍历

    for (K key : map.keySet()) { V value = map.get(key); }
    • 性能较低:如果需要 Value,每次循环还要多走一次哈希查找(get(key))。仅当只需要 Key 时使用
  • Map.forEach (Java 8+)

    map.forEach((k, v) -> { ... });
    • 评价:语法最优雅,底层基于 entrySet 遍历,兼顾了性能与美观。