覆盖基础、集合、并发、流、JVM、框架、新特性,每组多维度详细区分
1. ArrayList vs LinkedList
对比维度:底层结构、查询、头尾增删、中间插入、内存开销、遍历、适用场景
- 底层:ArrayList 动态数组;LinkedList 双向链表
- 查询随机下标:ArrayList O (1),直接寻址;LinkedList O (n),需遍历节点
- 尾部新增:ArrayList 扩容时复制数组,平均快;LinkedList 仅修改指针,无扩容
- 中间 / 头部插入删除:ArrayList 需要数组后移,性能差;LinkedList 只改前后指针,速度快
- 内存:ArrayList 连续内存,缓存友好;LinkedList 每个节点存 prev/next,额外内存开销大
- 遍历:ArrayList fori/foreach 更快;LinkedList 仅 foreach 友好,fori 巨慢
- 场景:ArrayList 绝大多数业务(查询多、尾部新增);LinkedList 频繁头尾增删、实现队列 / 栈
2. HashMap vs ConcurrentHashMap(JDK8)
维度:线程安全、锁机制、并发性能、扩容、null 键值、数据结构
- 线程安全:HashMap 不安全,并发丢数据、死循环;CHM 线程安全
- 锁:HashMap 无锁;CHM CAS + synchronized 锁住链表 / 红黑树头节点,粒度细
- null:HashMap 允许 1 个 null key、多个 null value;CHM key/value 都不允许 null
- 扩容:HashMap 并发扩容链表死循环;CHM 分段迁移,并发扩容安全
- 结构:数组 + 链表 + 红黑树;同 HashMap 结构,增加并发控制
- 性能:单线程 HashMap 更快;多线程 CHM 远优于 Collections.synchronizedMap
3. HashMap vs TreeMap vs LinkedHashMap
维度:有序性、底层、查询速度、排序规则、使用场景
- HashMap:无序,哈希表,O (1),无排序;普通键值存储
- LinkedHashMap:插入 / 访问有序,哈希表 + 双向链表,O (1);有序遍历、简易 LRU 缓存
- TreeMap:key 升序,红黑树,O (logn);需要按 key 自然排序场景
4. ArrayList vs CopyOnWriteArrayList
维度:线程安全、读写性能、内存、迭代、适用场景
- 安全:ArrayList 不安全;COWAL 线程安全
- 读:COWAL 无锁,读取极快;ArrayList 单线程读快
- 写:COWAL 写入复制完整新数组,开销极大;ArrayList 写轻量
- 迭代:COWAL 迭代快照,无并发修改异常;ArrayList 遍历修改抛异常
- 场景:COWAL 读多写少(配置缓存);ArrayList 单线程操作
5. synchronized vs Lock(ReentrantLock)
维度:底层、锁粒度、公平锁、中断、超时、可重入、释放、性能
- 底层:synchronized JVM 底层实现;Lock API 层面,AQS 队列
- 公平锁:synchronized 仅非公平;Lock 支持公平 / 非公平切换
- 中断等待:synchronized 阻塞不可中断;lockInterruptibly () 可中断
- 限时等待:synchronized 无限阻塞;tryLock (time) 超时自动放弃
- 释放:synchronized 自动释放;Lock 必须 finally 手动 unlock,否则死锁
- 条件变量:synchronized 只能 1 个 wait;Lock 支持多个 Condition
- 性能:低竞争 synchronized 优化后接近 Lock;高并发 Lock 性能更好
6. volatile vs synchronized
维度:作用、原子性、可见性、重排、锁、使用场景
- volatile:仅保证可见性、禁止指令重排;不保证原子性,无锁
- synchronized:可见性 + 原子性 + 禁止重排,独占锁
- 计数场景:volatile i++ 并发错乱;synchronized 自增安全
- 开销:volatile 轻量;synchronized 存在阻塞、上下文切换
- 场景:volatile 状态标记、双重检查锁单例;synchronized 复合操作并发保护
7. Runnable vs Callable
维度:返回值、异常、线程池、run 方法、Future
- Runnable run () 无返回值,不能抛出受检异常;Callable call () 有返回值,可抛异常
- 线程池提交:submit (Runnable) 无返回;submit (Callable) 返回 Future 获取结果
- 异常:Runnable 异常只能内部捕获;Callable 异常可通过 Future.get () 捕获
- 配合:Runnable 基础线程;Callable 异步需要获取执行结果场景
8. CountDownLatch vs CyclicBarrier
维度:复用、计数归 0 逻辑、使用场景
- CountDownLatch:一次性,主线程等多个子任务完成;计数归零不可重置
- CyclicBarrier:可循环复用,多个线程互相等待全部到达屏障再一起执行
- 举例:CDL 主线程等待批量查询全部完成;CB 多分段计算,全部算完合并结果
9. 并行流 parallelStream vs 自定义线程池 CompletableFuture
维度:线程池、IO 阻塞、线程隔离、控制、异常
- parallelStream:共用全局 ForkJoinPool,无隔离;IO 阻塞拖垮全局所有并行流
- CompletableFuture:可传入自定义线程池,任务隔离,不影响其他业务
- 控制力度:并行流无法自定义线程数;线程池可自定义核心、最大线程
- 适用:parallelStream 纯内存计算;CompletableFuture IO、RPC、隔离异步任务
10. Stream 中间操作 vs 终止操作
维度:执行时机、返回值、是否消费流、作用
- 中间操作 (filter/map/sorted/peek):惰性执行,返回新 Stream,不消费流,仅构建执行链
- 终止操作 (collect/forEach/count/findFirst):触发实际计算,消耗流,无 Stream 返回
- 关键:无终止操作,中间代码完全不执行;流只能执行一次终止操作
11. map() vs flatMap()
维度:返回类型、嵌套集合、使用场景
- map:T -> R,一对一转换,返回 Stream<R>;嵌套 List 会变成 Stream<List<T>>
- flatMap:T -> Stream<R>,扁平化,拆解嵌套集合,输出单层流
- 场景:简单字段映射用 map;集合嵌套拆解用 flatMap
12. orElse() vs orElseGet()
维度:执行时机、性能、参数类型
- orElse (T obj):无论 Optional 是否为空,入参对象 / 方法一定会执行;适合轻量常量
- orElseGet (Supplier):仅空值时才执行 Supplier;适合耗时查询、IO 操作
- 性能:耗时逻辑优先 orElseGet,避免无用计算
13. Optional.of() vs Optional.ofNullable()
维度:入参 null 处理、使用场景
- Optional.of (obj):obj 为 null 直接抛出 NPE;确定对象非空时使用
- Optional.ofNullable (obj):obj 为 null 返回 Optional.empty ();不确定对象是否为空通用
14. String + 拼接 vs StringBuilder vs StringBuffer
维度:线程安全、性能、适用场景
- String +:编译期少量拼接会优化 StringBuilder;循环大量拼接生成大量中间对象,性能极差
- StringBuilder:非线程安全,单线程高性能;日常循环字符串拼接首选
- StringBuffer:加 synchronized,线程安全,性能更低;极少多线程拼接场景使用
15. == vs equals()
维度:比较内容、对象 / 基本类型、重写规则
- ==:基本类型比较值;引用类型比较内存地址
- equals ():Object 默认同 ==;String、包装类重写为比较内容;自定义实体需手动重写 equals+hashCode 才能按业务字段对比
16. 基本数据类型 vs 包装类
维度:存储位置、默认值、null、装箱拆箱、缓存
- 基本类型:栈内存,有默认值,不能为 null,无对象头,开销小
- 包装类:堆对象,默认 null,自动装箱 valueOf、拆箱 xxxValue;-128~127 缓存,超出 == 失效
17. final 修饰变量 / 方法 / 类 三者对比
- final 变量:基本类型值不可改;引用类型地址不可改,内部属性可修改
- final 方法:不可被子类重写,运行期避免动态绑定,小幅优化
- final 类:禁止继承,所有方法隐式 final,如 String、Integer
18. 接口 (Interface JDK8+) vs 抽象类 abstract class
维度:构造方法、成员变量、多继承、方法、构造、静态代码块
- 抽象类:有构造方法,成员变量可任意修饰,单继承,可实例变量、代码块
- 接口:无构造,变量默认 public static final,可多实现;JDK8 default/static 方法、JDK9 私有方法;仅行为契约,无状态
19. 重载 Overload vs 重写 Override
维度:位置、方法名、参数、返回值、权限、异常
- 重载:同类,同名,参数列表不同;返回值无要求;任意权限
- 重写:父子类,同名同参数同返回;子类权限不能更严格;受检异常不能抛出更宽泛
20. try-with-resources vs 手动 close ()
维度:关闭时机、异常、代码冗余、泄漏风险
- try-with-resources:实现 AutoCloseable 自动关闭,无论正常 / 异常;关闭异常附 suppressed 异常,无资源泄漏,代码简洁
- 手动 close:必须 finally 关闭,代码冗余;忘记关闭导致文件句柄、连接泄漏
21. Error vs Exception
维度:是否捕获、产生原因、处理策略
- Error:系统级致命错误 (OutOfMemory、StackOverflow),无需捕获,程序无法恢复
- Exception:业务异常,分运行时异常 (无需捕获)、受检异常 (编译强制捕获),可业务兜底处理
22. 受检异常 vs 运行时异常
维度:编译校验、抛出声明、适用场景
- 受检异常:继承 Exception 非 RuntimeException;编译强制 try-catch 或 throws;IO、文件、网络等外部不可控异常
- 运行时异常:RuntimeException;编译不校验;空指针、数组越界、参数错误等代码逻辑问题
23. JVM 栈 vs 堆 vs 元空间 Metaspace
维度:存储内容、生命周期、GC、内存溢出
- 虚拟机栈:局部变量、栈帧;方法执行完毕释放;栈深度不够 StackOverflow
- 堆:所有对象实例、数组;GC 回收;对象过多 OOM 堆溢出
- 元空间:类元信息、常量、注解;本地内存;类加载过多 Metaspace 溢出
24. 标记清除 / 复制 / 标记整理 GC 算法对比
- 标记清除:速度快,产生大量内存碎片;老年代 CMS 使用
- 复制算法:无碎片,需要预留一半内存;新生代 Minor GC
- 标记整理:无碎片,移动对象开销大;老年代 G1、Serial Old
25. 泛型?extends T vs ? super T
维度:读写、使用场景
- ? extends T:上界通配符,只能读不能写;生产者场景 (获取数据)
- ? super T:下界通配符,只能写不能读;消费者场景 (存入数据)
- PECS 原则:Producer Extends,Consumer Super
26. Iterator 迭代器 vs fori 普通循环
维度:并发修改、遍历范围、索引操作
- Iterator:遍历中调用迭代器 remove 安全;无下标,无法精准定位元素
- fori 循环:可获取下标,支持随机访问;遍历内集合 add/remove 触发并发修改异常
27. @Transactional public 方法 vs private 方法
维度:AOP 拦截、事务生效
- public:Spring AOP 动态代理可拦截,事务正常生效
- private:代理无法拦截私有方法,注解失效,无事务控制
28. new Thread () 手动创建 vs 线程池 ThreadPoolExecutor
维度:复用、开销、管控、拒绝策略
- new Thread:线程一次性,频繁创建销毁开销巨大;无线程管控,线程无限暴涨无限制
- 线程池:复用线程,控制最大并发、阻塞队列、拒绝策略;统一管控异步任务,生产环境强制使用
29. List.subList () vs 新建 ArrayList 拷贝集合
维度:数据关联、内存、修改影响
- subList:原集合视图,不创建新对象;修改分片 / 原集合互相影响;clear 仅清空视图不释放原数据
- new ArrayList<>(list):完整拷贝新集合,数据完全隔离;互不影响,占用双倍内存
30. 串行流 stream () vs 并行流 parallelStream ()
维度:线程池、顺序、IO 任务、数据量、性能
- 串行流:单线程执行,有序;无全局线程池抢占;适合小数据、有序业务逻辑
- 并行流:ForkJoin 公共池多线程;不保证遍历顺序;适合纯内存大数据计算;禁止 IO、RPC 阻塞任务,会污染全局并行任务池

402

被折叠的 条评论
为什么被折叠?



