1. Java 基本数据类型有哪些?
场景:面试官问「String 是不是基本类型?」
答案要点:8 种基本类型:byte, short, int, long, float, double, char, boolean。String 是引用类型。
追问链条:
问:为什么需要基本类型而不是全部对象?
答:基本类型更轻量,性能更高。问:对应的包装类是什么?
答:Byte, Short, Integer, Long, Float, Double, Character, Boolean。问:装箱/拆箱有性能问题吗?
答:有,频繁装拆箱可能导致额外开销。
2. == 和 equals 的区别?
场景:字符串比较
"abc" == new String("abc")
。答案要点:
==
比较引用地址;equals
比较内容(String 重写了 equals)。追问链条:
问:为什么 String 要重写 equals?
答:否则 equals 也只是比较引用。问:哪些类没重写 equals?
答:Object 默认 equals 是==
。问:重写 equals 时为什么要重写 hashCode?
答:保证在集合(HashMap/HashSet)中一致性。
3. String、StringBuilder、StringBuffer 区别?
场景:面试官问「拼接字符串用哪个效率高」。
答案要点:
String:不可变,每次拼接生成新对象。
StringBuilder:可变,非线程安全,效率高。
StringBuffer:可变,线程安全,效率比 StringBuilder 低。
追问链条:
问:为什么 String 设计成不可变?
答:安全(常量池)、缓存、线程安全。问:多线程拼接用哪个?
答:StringBuffer 或用外部同步控制 StringBuilder。问:+ 拼接底层怎么实现?
答:编译期用 StringBuilder 优化。
4. ArrayList 和 LinkedList 区别?
场景:问「插入/查询哪个更快」。
答案要点:
ArrayList:基于数组,查询快 O(1),插入/删除慢 O(n)。
LinkedList:基于双向链表,插入/删除快 O(1),查询慢 O(n)。
追问链条:
问:如果在尾部插入呢?
答:ArrayList 均摊 O(1),LinkedList O(1)。问:为什么 LinkedList 查询慢?
答:需遍历链表节点。问:在实际项目用哪个多?
答:ArrayList 用得更多,因查询远多于插入。
5. HashMap 的底层实现?
场景:问「HashMap 为什么快?」
答案要点:JDK1.8 以后,数组 + 链表 + 红黑树。负载因子默认 0.75,扩容翻倍。
追问链条:
问:为什么引入红黑树?
答:链表过长(>8)时避免 O(n),降到 O(log n)。问:为什么负载因子是 0.75?
答:空间和查找效率的折中。问:线程安全吗?
答:不安全,线程安全可用 ConcurrentHashMap。
6. ConcurrentHashMap 的原理?
场景:问「多线程下怎么保证安全」。
答案要点:
JDK1.7:分段锁(Segment)。
JDK1.8:CAS + synchronized 锁粒度更小。
追问链条:
问:为什么不用全局锁?
答:全局锁效率低,分段锁并发度更高。问:JDK1.8 为什么改?
答:优化锁粒度,减少 Segment 内部冲突。问:适合替代 HashMap 吗?
答:适合并发场景,但写性能低于非并发 HashMap。
7. Java 的异常体系?
场景:问「throw 和 throws 区别」。
答案要点:
Throwable → Error(不可处理)、Exception(可处理)。
受检异常(Checked):必须捕获或抛出。
非受检异常(RuntimeException):可不捕获。
追问链条:
问:为什么有 Checked Exception?
答:提醒开发者必须处理异常。问:常见的 RuntimeException?
答:NullPointerException, IndexOutOfBoundsException。问:finally 一定会执行吗?
答:除非调用 System.exit 或线程中断。
8. final、finally、finalize 区别?
场景:问「final 和 finally 一样吗?」
答案要点:
final:修饰类(不可继承)、方法(不可重写)、变量(常量)。
finally:异常处理语句块。
finalize:Object 方法,GC 前调用(不推荐使用)。
追问链条:
问:final 变量必须初始化吗?
答:是,必须赋值一次。问:finally 能不执行吗?
答:在 System.exit 时不会。问:finalize 为什么不推荐?
答:不确定性强,性能差。
9. static 关键字作用?
场景:问「static 在项目里怎么用?」
答案要点:
修饰变量:类变量,所有对象共享。
修饰方法:类方法,可通过类名直接调用。
修饰代码块:类加载时执行一次。
追问链条:
问:静态方法能调用非静态变量吗?
答:不能,因为非静态变量依赖实例。问:static 修饰内部类?
答:静态内部类不依赖外部类对象。问:项目常见应用?
答:工具类、单例模式。
10. 接口和抽象类的区别?
场景:问「为什么有了抽象类还要接口?」
答案要点:
接口:定义规范(Java8 以后可有默认方法)。
抽象类:定义抽象方法 + 部分实现,支持构造函数。
追问链条:
问:能多继承吗?
答:接口可多实现,类只能单继承。问:什么时候用接口?
答:更强调规范,如 DAO 层。问:什么时候用抽象类?
答:有共享逻辑的基类场景。
11. Java 内存模型(JMM)?
场景:问「volatile 的作用」。
答案要点:JMM 规定了多线程间如何通过内存交互,关键问题:可见性、有序性、原子性。
追问链条:
问:volatile 保证什么?
答:保证可见性和有序性,但不保证原子性。问:如何保证原子性?
答:使用 synchronized 或 Atomic 类。问:指令重排是什么?
答:编译器/CPU 优化指令顺序,可能导致线程安全问题。
12. synchronized 和 ReentrantLock 区别?
场景:问「项目中锁用哪个多」。
答案要点:
synchronized:Java 关键字,JVM 层面实现。
ReentrantLock:Java API,功能更强(公平锁、可中断、条件变量)。
追问链条:
问:谁性能更高?
答:JDK1.6 后 synchronized 优化,性能差距不大。问:什么时候用 ReentrantLock?
答:需要超时获取、可中断、多个条件时。问:什么是可重入?
答:同一线程可重复获取锁而不死锁。
13. JVM 内存结构?
场景:问「对象在哪个区?」
答案要点:
堆(对象、数组)。
方法区(类信息、常量池)。
栈(局部变量)。
程序计数器。
追问链条:
问:栈和堆的区别?
答:栈存储局部变量,生命周期随线程;堆存储对象,GC 管理。问:方法区和堆区别?
答:方法区存储类元信息,堆存储实例。问:常量池在方法区吗?
答:JDK8 前在永久代,之后在 Metaspace。
14. 垃圾回收(GC)算法?
场景:问「为什么要分代回收」。
答案要点:
标记-清除。
复制算法(新生代)。
标记-整理(老年代)。
分代收集:针对对象生命周期优化。
追问链条:
问:为什么新生代用复制?
答:大部分对象朝生夕死,复制效率高。问:老年代为什么不用复制?
答:对象存活率高,复制代价大。问:常见 GC 器有哪些?
答:Serial, Parallel, CMS, G1, ZGC, Shenandoah。
15. transient 关键字作用?
场景:问「对象序列化时怎么忽略某个字段」。
答案要点:
transient
修饰字段,序列化时不会保存。追问链条:
问:静态变量会被序列化吗?
答:不会,属于类而非对象。问:如果必须序列化怎么办?
答:手动实现 writeObject/readObject。问:项目中常见应用?
答:敏感信息(如密码)、不需要持久化的缓存字段。
16. Java 创建线程的方式有哪些?
场景:问「如果要执行一个并发任务,怎么创建线程?」
答案要点:
继承 Thread 类。
实现 Runnable 接口。
实现 Callable + FutureTask。
线程池 ExecutorService。
追问链条:
问:Runnable 和 Callable 区别?
答:Callable 可返回结果、抛出异常。问:为什么推荐线程池?
答:减少频繁创建销毁开销,统一管理。问:项目里常用哪种?
答:基本都用线程池。
17. sleep() 和 wait() 的区别?
场景:问「线程暂停和释放锁有什么不同?」
答案要点:
sleep():线程暂停但不释放锁。
wait():暂停并释放锁,需配合 synchronized 使用。
追问链条:
问:wait 必须在 synchronized 中调用吗?
答:是,否则抛 IllegalMonitorStateException。问:notify 和 notifyAll 区别?
答:notify 唤醒一个线程,notifyAll 唤醒所有。问:项目中常用吗?
答:更常用的是并发工具类(如 CountDownLatch、Semaphore)。
18. volatile 能保证原子性吗?
场景:问「volatile 修饰 i++ 安全吗?」
答案要点:volatile 只能保证可见性和有序性,不保证复合操作的原子性。
追问链条:
问:为什么 i++ 不是原子操作?
答:包含读取、加一、写回三个步骤。问:如何保证原子性?
答:使用 synchronized 或 AtomicInteger。问:什么时候只用 volatile?
答:配置刷新、状态标志。
19. ThreadLocal 的作用?
场景:问「Web 项目里为什么要用 ThreadLocal 保存用户信息?」
答案要点:为每个线程提供独立变量副本,避免共享冲突。常用于存储用户上下文、数据库连接。
追问链条:
问:ThreadLocal 会造成内存泄漏吗?
答:可能,若不 remove(),线程池中的线程不会释放副本。问:它的底层原理?
答:Thread → ThreadLocalMap 存储。问:怎么避免内存泄漏?
答:用完后及时 remove()。
20. Java IO 和 NIO 区别?
场景:问「为什么高并发用 NIO?」
答案要点:
IO:面向流,阻塞。
NIO:面向缓冲区,非阻塞,支持多路复用。
追问链条:
问:NIO 核心组件?
答:Channel、Buffer、Selector。问:NIO 一定比 IO 快吗?
答:不一定,小规模连接 IO 简单高效。问:NIO 在哪里用?
答:网络编程(Netty)。
21. 反射的原理?
场景:问「Spring 是怎么通过反射创建 Bean 的?」
答案要点:反射允许在运行时获取类信息(Class 对象),动态调用构造器、方法、字段。
追问链条:
问:反射的性能如何?
答:比直接调用慢,因需检查安全、动态查找。问:如何优化反射性能?
答:缓存 Method/Field 对象。问:项目中常见应用?
答:Spring IOC、ORM 框架。
22. 泛型在 Java 中的意义?
场景:问「为什么要有泛型,直接用 Object 不行吗?」
答案要点:泛型保证类型安全,避免强制类型转换,提升代码复用性。
追问链条:
问:Java 泛型是如何实现的?
答:编译期检查 + 类型擦除。问:为什么叫类型擦除?
答:运行时泛型信息被擦除,只保留 Object 或上限类型。问:能获取泛型参数的实际类型吗?
答:不能直接获取,但可通过反射获取部分信息。
23. 注解的原理?
场景:问「Spring @Autowired 是怎么生效的?」
答案要点:注解本质是接口,配合反射 + 注解处理器(APT)或运行时解析,实现功能增强。
追问链条:
问:注解分几类?
答:源码级、编译期(APT)、运行时。问:注解能继承吗?
答:不直接支持,但可用 @Inherited。问:自定义注解怎么实现?
答:定义 @interface + 元注解(@Target, @Retention)。
24. equals 和 hashCode 的关系?
场景:问「为什么要同时重写 hashCode?」
答案要点:
equals 相等 → hashCode 必须相等。
hashCode 相等 → equals 不一定相等。
追问链条:
问:如果只重写 equals 会怎样?
答:可能在 HashSet 中重复插入。问:hashCode 默认实现是什么?
答:Object 的 hashCode 基于对象内存地址。问:怎么重写 hashCode?
答:常用 Objects.hash()。
25. Java 序列化机制?
场景:问「对象如何持久化存储?」
答案要点:实现 Serializable 接口,使用 ObjectOutputStream / ObjectInputStream。
追问链条:
问:为什么要序列化?
答:对象持久化、网络传输。问:serialVersionUID 的作用?
答:保证反序列化版本一致性。问:如果不想序列化某字段?
答:用 transient 修饰。
26. 什么是反序列化漏洞?
场景:安全面试问「为什么要谨慎使用 Java 序列化?」
答案要点:攻击者可构造恶意字节流,反序列化时触发恶意代码。
追问链条:
问:如何避免?
答:禁止反序列化不可信数据。问:有替代方案吗?
答:使用 JSON 序列化。问:Spring Boot 默认用什么?
答:Jackson/JSON。
27. 什么是内部类?有什么类型?
场景:问「成员内部类和静态内部类的区别?」
答案要点:
成员内部类:依赖外部类实例。
静态内部类:不依赖外部类实例。
局部内部类:定义在方法里。
匿名内部类:常用于回调。
追问链条:
问:内部类能访问外部类的 private 吗?
答:能,编译器会生成桥接代码。问:为什么用匿名内部类?
答:简化回调实现(Java8 前)。问:Java8 后更常用什么?
答:Lambda 表达式。
28. 什么是 Lambda 表达式?
场景:问「Java8 为什么引入 Lambda?」
答案要点:Lambda 是匿名函数,简化函数式编程,常与 Stream API 结合。
追问链条:
问:底层原理?
答:通过 invokedynamic 指令实现。问:和匿名内部类区别?
答:语法简洁,性能更优。问:项目中常用在哪?
答:集合操作、异步回调。
29. 什么是函数式接口?
场景:问「为什么 Lambda 只能用在函数式接口上?」
答案要点:函数式接口 = 只有一个抽象方法的接口(@FunctionalInterface)。
追问链条:
问:常见的函数式接口?
答:Runnable, Callable, Comparator, Consumer, Supplier。问:为什么 @FunctionalInterface 可选?
答:只是提醒和编译期检查。问:能不能有默认方法?
答:可以,但抽象方法只能有一个。
30. Java Stream API 的作用?
场景:问「为什么要用 Stream,而不是 for 循环?」
答案要点:提供声明式集合操作(map、filter、reduce),支持并行流,代码简洁。
追问链条:
问:Stream 是惰性执行的吗?
答:是,只有遇到终止操作才执行。问:并行流一定比串行流快?
答:不一定,小数据量下反而慢。问:常见场景?
答:数据过滤、聚合统计。
31. JVM 内存结构有哪些?
场景:问「一个 Java 程序运行时,内存是如何划分的?」
答案要点:
程序计数器
虚拟机栈
本地方法栈
堆
方法区(元空间)
追问链条:
问:堆里存什么?
答:对象实例。问:栈里存什么?
答:局部变量、方法调用。问:方法区是什么?
答:存放类信息、常量、静态变量。
32. 类加载过程是什么?
场景:问「类是怎么被加载到 JVM 的?」
答案要点:加载 → 验证 → 准备 → 解析 → 初始化。
追问链条:
问:初始化阶段做了什么?
答:执行静态变量赋值和静态代码块。问:什么是双亲委派模型?
答:类加载先委托父加载器。问:为什么要有双亲委派?
答:避免重复加载、保证安全。
33. 什么是 GC Roots?
场景:问「垃圾回收时,怎么判断对象是否存活?」
答案要点:从 GC Roots 出发可达的对象是存活的。
常见 GC Roots:虚拟机栈引用、本地方法栈引用、静态变量、常量。
追问链条:
问:有哪些垃圾回收算法?
答:标记清除、复制、标记整理、分代收集。问:Minor GC 和 Full GC 区别?
答:Minor GC 只收集新生代,Full GC 会收集整个堆和方法区。问:如何避免频繁 Full GC?
答:减少大对象、优化内存分配。
34. JVM 调优常用参数有哪些?
场景:问「如果线上频繁 GC 怎么处理?」
答案要点:
-Xms/-Xmx
:堆大小-Xmn
:新生代大小-XX:+PrintGCDetails
:GC 日志
追问链条:
问:如何查看 GC 情况?
答:jstat、GC 日志。问:如何定位内存泄漏?
答:jmap dump → MAT 分析。问:堆外内存怎么调优?
答:-XX:MaxDirectMemorySize
。
35. String 为什么是不可变的?
场景:问「为什么 String 修改会生成新对象?」
答案要点:
字符串常量池需要安全性和复用。
线程安全。
缓存 hashCode。
追问链条:
问:StringBuilder 和 StringBuffer 区别?
答:StringBuffer 线程安全,StringBuilder 非线程安全。问:为什么推荐用 StringBuilder?
答:性能更好。问:String.intern() 的作用?
答:将字符串加入常量池。
36. equals 和 == 的区别?
场景:问「比较两个对象是否相等?」
答案要点:
==
比较引用或基本类型值。equals 比较内容,默认继承 Object 时等同于
==
。
追问链条:
问:包装类用 == 会怎样?
答:可能比较引用,容易出错。问:Integer 缓存范围?
答:-128 ~ 127。问:项目里怎么避免坑?
答:统一用 equals。
37. final 关键字的作用?
场景:问「如何定义常量?」
答案要点:
修饰类:不能继承。
修饰方法:不能重写。
修饰变量:值不能改变。
追问链条:
问:final 修饰对象能变吗?
答:引用不能变,但对象内容可变。问:final 和 immutability 区别?
答:final 只是引用不可变,immutable 是内容不可变。问:项目中常见用途?
答:工具类、配置常量。
38. static 关键字的作用?
场景:问「为什么工具类的方法都是 static?」
答案要点:
修饰变量:类级共享。
修饰方法:无需实例化即可调用。
修饰代码块:类加载时执行一次。
追问链条:
问:静态变量存放在哪里?
答:方法区(元空间)。问:静态方法能访问非静态变量吗?
答:不能,需要实例。问:项目中常见用途?
答:单例、工具类。
39. 接口和抽象类的区别?
场景:问「什么时候用接口,什么时候用抽象类?」
答案要点:
接口:行为规范,多继承。
抽象类:模板,支持字段、构造方法。
追问链条:
问:Java8 接口有什么新特性?
答:默认方法、静态方法。问:接口能有变量吗?
答:只能有常量(public static final)。问:设计时如何选择?
答:抽象类用于继承体系,接口用于扩展。
40. 什么是多态?
场景:问「为什么要用父类引用指向子类对象?」
答案要点:
编译看左边,运行看右边。
提高扩展性。
追问链条:
问:重写和重载区别?
答:重写是运行时,多态实现;重载是编译期。问:多态能提升性能吗?
答:不是性能,而是设计灵活性。问:项目里常见场景?
答:接口编程、策略模式。
41. 什么是异常体系?
场景:问「为什么要区分 checked 和 unchecked 异常?」
答案要点:
Exception(受检异常)必须处理。
RuntimeException(非受检异常)可以不处理。
追问链条:
问:常见的受检异常?
答:IOException, SQLException。问:常见的运行时异常?
答:NullPointerException, IndexOutOfBounds。问:项目里怎么设计异常?
答:统一异常处理(全局异常捕获)。
42. Java 内存模型 JMM 是什么?
场景:问「为什么多线程需要 synchronized?」
答案要点:JMM 定义了线程如何通过主内存和工作内存交互,保证可见性、有序性、原子性。
追问链条:
问:JMM 三大特性?
答:原子性、可见性、有序性。问:volatile 保证了哪些?
答:可见性和有序性,不保证原子性。问:happens-before 原则是什么?
答:JMM 中的内存可见性规则。
43. synchronized 和 ReentrantLock 的区别?
场景:问「为什么有了 synchronized 还要 Lock?」
答案要点:
synchronized:JVM 层实现,语法简单。
Lock:API 层实现,功能更丰富(可中断、公平锁、条件变量)。
追问链条:
问:Lock 如何释放?
答:必须在 finally 里 unlock。问:ReentrantLock 为什么叫可重入?
答:同一线程可以多次获取锁。问:项目中什么时候用 Lock?
答:复杂锁逻辑、需要尝试锁时。
44. 什么是 AQS?
场景:问「CountDownLatch 为什么能实现等待?」
答案要点:AQS(AbstractQueuedSynchronizer)基于 CLH 队列实现,提供独占/共享锁语义。
追问链条:
问:AQS 支撑了哪些类?
答:ReentrantLock, CountDownLatch, Semaphore。问:AQS 如何实现排队?
答:通过 state 状态和队列。问:项目里用过哪些?
答:常用 CountDownLatch 实现任务并发。
45. Java 的四种引用类型?
场景:问「为什么要有软引用、弱引用?」
答案要点:
强引用:普通引用,不会回收。
软引用:内存不足才回收。
弱引用:下次 GC 必回收。
虚引用:无法获取对象,仅用于跟踪 GC。
追问链条:
问:软引用常用场景?
答:缓存。问:弱引用常见用法?
答:ThreadLocal Map。问:虚引用呢?
答:管理堆外内存。
46. 什么是类加载器?
场景:问「Java 是怎么找到类的?」
答案要点:
Bootstrap ClassLoader
Extension ClassLoader
Application ClassLoader
自定义 ClassLoader
追问链条:
问:如何实现热加载?
答:自定义 ClassLoader。问:为什么要有自定义类加载器?
答:插件化、热更新。问:OSGi 是怎么做的?
答:模块化 ClassLoader。
47. 什么是双亲委派模型?
场景:问「为什么自己写的 String 类不会被加载?」
答案要点:加载请求先交给父加载器,父加载器无法完成再自己加载。
追问链条:
问:为什么要设计双亲委派?
答:保证核心类安全性。问:什么时候会破坏双亲委派?
答:Tomcat、SPI。问:如何打破?
答:自定义 ClassLoader。
48. Java 常用设计模式有哪些?
场景:问「项目里用过哪些设计模式?」
答案要点:单例、工厂、代理、策略、观察者。
追问链条:
问:单例模式如何实现线程安全?
答:双重检查锁、静态内部类。问:工厂模式有什么好处?
答:解耦对象创建和使用。问:代理模式在 Spring 哪里用到?
答:AOP。
49. 什么是 Optional?
场景:问「Java8 为什么引入 Optional?」
答案要点:避免 NullPointerException,提供函数式 API(map, flatMap, orElse)。
追问链条:
问:Optional 是替代 null 吗?
答:不是,而是辅助工具。问:项目里能用 Optional 作为字段吗?
答:不推荐。问:Optional 常见用法?
答:返回值包装。
50. Java17 有哪些新特性?
场景:问「公司升级到 Java17,有哪些不同?」
答案要点:
sealed classes(密封类)
pattern matching for instanceof
switch 表达式增强
JDK 内置 G1/ZGC 优化
追问链条:
问:为什么密封类有用?
答:限制继承,增强可维护性。问:switch 表达式和旧的有啥不同?
答:支持箭头语法和返回值。问:Java17 适合哪些企业?
答:长期支持 LTS,适合迁移。