Java基础高频面试题

使用说明

这是 01-Java基础 全组的压轴复盘篇:把前面九个板块的必考点收拢成一份速答题库。每题只给"速答"(面试时开口就要说的那几句),详细展开全部指路既有篇目——答题靠速答,讲透靠回读。建议自测方式:只看题目,先自己说 30 秒,再对照速答找差距。


一、数据类型(01-数据类型体系)

1. == 和 equals 的区别?

速答:== 比较基本类型的值、引用类型的地址;equals 默认就是 ==(Object 原始实现),但 String、Integer 等都重写成了比较内容。所以问区别,本质是问"有没有被重写"。

展开Object通用方法

2. 为什么重写 equals 必须重写 hashCode?

速答:契约要求"equals 相等则 hashCode 必须相等"。只重写 equals 时,两个"相等"对象 hashCode 不同,放进 HashMap 会被散列到不同桶,contains/get 查不到——集合行为直接出错。

展开Object通用方法

3. Integer 缓存是什么?Integer a=127, b=127; a==b 呢?

速答:自动装箱走 Integer.valueOf(),对 -128~127 走缓存池返回同一对象,所以 127<mark>127 为 true;128</mark>128 超出缓存,各自 new 对象,== 比地址为 false。结论:包装类比较永远用 equals

展开缓存池机制(Cache Pool)

4. 自动拆箱有什么坑?

速答:三连坑——== 比较两个包装类比地址;包装类为 null 时拆箱抛 NPE(典型:三元运算符 flag ? intVal : integerVal 自动拆箱);循环里 Long sum += i 产生大量临时对象。缓存池只能救 -128~127。

展开自动装拆箱

二、核心类(02-核心类详解)

5. String 为什么设计成不可变?

速答:三点——字符串常量池复用的前提(池里共享一个对象,可变就互相污染);hashCode 可以缓存(HashMap key 稳定);天然线程安全。实现上 private final char[] 且不提供修改入口。

展开String详解

6. String、StringBuilder、StringBuffer 怎么选?

速答:拼接频繁用 StringBuilder;多线程共享拼接用 StringBuffer(方法加 synchronized);String 适合不变量。str += 在循环里每次都 new 对象,是典型反模式。

展开StringBuilder系列

7. BigDecimal 为什么能保证精度?有什么坑?

速答:用"无标度值+标度"存十进制数,不走二进制浮点。坑:new BigDecimal(0.1) 传入的就已经不精确,要用字符串构造或 valueOf;除不尽必须指定舍入模式否则抛异常;equals 连 scale 一起比,0.10.10 不相等,比数值用 compareTo。

展开BigDecimal

三、面向对象(03-面向对象核心)

8. 重载和重写的区别?("两同两小一大")

速答:重载是同一个类里方法名同、参数列表不同(编译期绑定);重写是子类覆盖父类方法,规则"两同两小一大"——方法名参数表相同,返回值和异常范围更小或相同,访问权限更大或相同(编译期看引用类型,运行期看对象实际类型)。

展开重写与重载编译时多态和运行时多态

9. 接口和抽象类的区别?

速答:抽象类是"是什么"(单继承,可有状态/构造器/具体实现),接口是"能做什么"(多实现,Java 8 前纯规范,之后可有 default/static 方法但无实例字段)。选型:共享代码用抽象类,定义能力用接口。

展开抽象类与接口抽象类与接口的区别

10. Java 为什么不支持多重继承?接口多实现为什么又可以?

速答:类的多继承有菱形歧义(两个父类对同一方法各有实现,子类不知道听谁的);接口多实现无歧义,因为 Java 8 前接口无实现,Java 8 后 default 冲突被编译器强制要求重写(可用 A.super.xxx() 显式指定),歧义在编译期消灭。

展开为什么Java不支持多重继承?接口多实现

11. 两个接口有同名 default 方法,实现类怎么办?

速答:编译报错,必须重写。想复用某一方的实现用 接口名.super.方法名()。补充裁决顺序:类/父类方法永远优先于接口 default(类优先原则);子接口的 default 优先于父接口。

展开接口多实现

四、关键字(04-关键字)

12. final 有哪几种用法?

速答:修饰类不能被继承(String)、修饰方法不能被重写、修饰变量不可重新赋值——基本类型是值不变,引用类型是指向不变(对象内容仍可改)。另外 final + 语义上不可变,才构成真正的不可变对象。

展开final关键字

13. static 有哪些用法?

速答:静态变量(类级别共享,方法区/元空间)、静态方法(无 this,不能直接访问实例成员)、静态代码块(类加载时执行一次)、静态内部类(不持有外部类引用,单例模式常用)。

展开static关键字

五、核心机制(05-核心机制)

14. 反射是什么?有什么用?代价是什么?

速答:运行时获取 Class 对象、动态访问字段/方法/构造器的能力。价值:框架的基石(Spring IOC、MyBatis、序列化都靠它)。代价:绕过编译期检查、有安全检查开销(可用 setAccessible)、优化器难以内联,性能低于直接调用。

展开Class对象与反射机制

15. JDK 动态代理和 CGLIB 有什么区别?

速答:JDK 动态代理基于接口(Proxy+InvocationHandler,运行时生成实现同接口的代理类);CGLIB 基于继承(ASM 生成目标类子类,覆写非 final 方法)。Spring 默认:有接口用 JDK,无接口用 CGLIB。

展开动态代理

16. 受检异常和非受检异常怎么区分?

速答:受检异常(IOException 等)继承 Exception 但不继承 RuntimeException,编译器强制 try-catch 或 throws;非受检异常(RuntimeException 及其子类如 NPE、越界)编译器不管,属于程序 bug,正确姿势是修代码而不是 catch 了事。Error 一律不捕获。

展开异常体系

17. 什么是泛型擦除?

速答:泛型只存在于编译期,编译后 List<String>List<Integer> 都是 List(原始类型),运行期拿不到泛型实参(能通过 getGenericSuperclass 等拿到声明处的签名)。代价:不能 new T()、不能泛型数组、不能基本类型。桥方法是为了保证擦除后多态仍然正确。

展开泛型详解

18. 枚举实现单例为什么天然安全?

速答:JVM 层面禁止反射创建枚举实例(Constructor.newInstance 遇到枚举直接抛 IllegalArgumentException),且枚举序列化由 JVM 保证——同一常量反序列化后仍是同一实例。普通单例要手动防反射(构造器抛异常)、防序列化(readResolve),枚举两样都自带。

展开枚举

19. Lambda 捕获局部变量为什么要求 final(或事实最终)?

速答:Lambda 捕获的是变量的值副本,存在合成字段里;如果允许变量再被修改,副本与原变量会各改各的,语义混乱,所以编译器强制"捕获后不可再改"。成员变量不受限——通过 this 引用,改的就是对象字段本身。

展开Lambda与函数式接口

20. map 和 flatMap 的区别?Stream 为什么惰性?

速答:map 一进一出(元素换形态),flatMap 一进多出(把每个元素摊平成流再拼接,适合处理嵌套结构)。惰性是因为中间操作只"记账",终端操作触发时把整条链融合成一次遍历执行——还能靠 limit 短路提前终止,比手写多层循环少跑趟数。

展开Stream与Optional

21. 字节流和字符流怎么选?transient 是干什么的?

速答:字节流(InputStream/OutputStream)处理一切原始数据;字符流(Reader/Writer)处理文本,多一层按字符集编解码——文本读写永远显式指定编码。transient 修饰的字段不参与 Java 序列化,反序列化后为默认值(密码、缓存句柄等敏感/临时字段用)。

展开IO流体系

六、JVM(07-JVM与内存模型 + 08-java的优势)

22. JVM 内存区域怎么划分?哪些线程共享?

速答:线程共享——堆(对象实例)、方法区(Java 8 起由元空间实现,存类信息);线程私有——虚拟机栈(栈帧:局部变量表+操作数栈)、本地方法栈、程序计数器。OOM 多发在堆和元空间,StackOverflowError 发生在栈。

展开JVM与内存模型

23. 类加载过程和双亲委派是什么?

速答:加载→验证→准备→解析→初始化五阶段。双亲委派:收到加载请求先交给父加载器(应用→平台→启动),父类搞不定才自己干——保证核心类(如 String)不被用户自定义类替换,安全且避免重复加载。

展开类加载机制

24. GC 怎么判断对象该不该回收?

速答:可达性分析——从 GC Roots(栈帧局部变量、静态变量、常量、JNI 引用等)向下搜索,搜不到的就是可回收。引用计数法有循环引用缺陷所以 JVM 不用。finalize/四种引用(强软弱虚)影响回收时机。

展开垃圾回收与GC算法

25. 内存泄漏和内存溢出的区别与联系?

速答:泄漏是"该死的对象没死"(被无意识引用拖住,GC 够不着),慢性病,症状是老年代持续走高;溢出是"内存彻底不够用"抛 OOM,急性发作。持续泄漏迟早引发堆溢出,但溢出不一定是泄漏(也可能是堆太小)。典型泄漏:静态集合、ThreadLocal 不 remove、监听器不注销。

展开内存泄漏内存溢出

26. Java 为什么能跨平台?"写一次到处跑"的完整链路?

速答:源码编译成平台无关的字节码,各平台的 JVM 负责把字节码翻译成本地机器码。性能靠 JIT 编译热点代码补回来(接近本地代码),快速启动场景用 AOT 提前编译。链路:.java → javac → .class → JVM(解释器 + JIT)→ 机器码

展开java的优势字节码JIT编译

七、其他(09-其他)

27. 内部类有哪几种?各用在什么场景?

速答:成员内部类(依赖外部类实例,少见)、静态内部类(不持有外部引用,Builder/单例 Holder 常用)、局部内部类(方法内,罕见)、匿名内部类(实现接口/继承类的单次使用,Java 8 后多数被 Lambda 替代,但"捕获 effectively final"的规则一脉相承)。

展开内部类

28. 位运算有哪些实战技巧?

速答:判断奇偶 n & 1;乘除 2 的幂用移位;n & (n-1) 消去最低位的 1(统计 1 的个数/判断 2 的幂);异或找"只出现一次的数"(a^a=0);HashMap 里 hash & (n-1) 定位桶就是取模的位运算优化。

展开java中的位运算技巧


复盘建议

  • 全对:可以往 容器高频面试题并发高频面试题 进阶了,那两份是同一套"速答+指路"体例;
  • 错 3 题以上:别急着背答案,点开对应篇目回读原理——这套题库每道题背后都有完整篇目撑腰,这也是本组和其他八组并存的意义。

⬅️ 内部类 🏠 00-Java ➡️ 00-Java