Java 面试高频:反射机制与异常体系全面解析

反射

回答面试官问题的时候,可以不用这么一问一答的方式:

比如在讲了什么是反射之后,我们就可以顺手的提一下为什么反射的性能这么低?以及反射的优缺点!

那你既然说了这么多?你知道怎么去用反射去创建一个对象吗?【补】

如果前面在回答的过程中,提到了底层框架用到了反射,那你可以提一下底层框架的哪些地方用到了反射!

什么是反射?

反射就是 Java 在运行期间动态获取类的信息,并操作类的属性、方法和构造方法的机制。

比如可以通过类名获取 Class 对象,再创建对象、调用方法、修改字段。 它的优点是灵活,常用于框架底层,比如 Spring;缺点是性能相对差,并且会破坏封装性。

反射为什么性能这么低?

反射性能低主要是因为它是运行时动态解析和调用,不像普通方法调用那样在编译期就确定好。

普通方法调用可以被 JVM 优化,比如内联;而反射调用需要做权限检查、方法查找、参数封装和类型校验,这些都会带来额外开销。 所以反射更适合框架层使用,不适合在高频业务逻辑里大量调用。

反射的优缺点是什么

反射的优点是灵活性高,可以在运行时动态创建对象、调用方法、访问属性,所以很多框架比如 Spring、MyBatis 底层都会用到反射。

缺点是性能比普通调用低 ,因为需要运行时解析、权限检查和类型校验;另外反射可以访问私有成员,可能会破坏封装性,代码可读性和安全性也会变差。

所以说还是要先去++获取一下对应类的class对象,你都知道有哪些方式吗++?

获取Class对象的三种方式是什么,各自的区别是什么?

获取 Class 对象主要有三种方式:

第一种是:

复制代码

Class clazz = User.class;

这种方式最安全,编译期 就能检查,一般最常用。

第二种是:

复制代码

Class clazz = user.getClass();

这种方式必须先有对象,获取的是运行时对象的真实类型

第三种是:

复制代码

Class clazz = Class.forName("com.xxx.User");

这种方式通过类的全限定名获取,会触发类加载,常用于配置文件、框架或 JDBC 场景。

所以前面我们获取了class对象的主要目的就是为了在这个地方用,反射的方式来创建一个对象!

如何通过反射创建一个对象

通过反射创建对象,一般是先获取 Class 对象,再获取构造方法,最后调用 newInstance()。【无参构造】

复制代码

Class<User> clazz = User.class; User user = clazz.getDeclaredConstructor().newInstance();

如果是有参构造,可以这样:

复制代码

Constructor<User> constructor = clazz.getDeclaredConstructor(String.class, int.class); User user = constructor.newInstance("张三", 18);

现在更推荐用 getDeclaredConstructor().newInstance(),不推荐直接用 clazz.newInstance(),因为后者已经不建议使用了。

既然你都知道用反射去创建一个对象了,++那么怎么用反射来调用私有字段和私有方法呢++?

如何通过反射调用私有字段和私有方法

可以通过 getDeclaredField()getDeclaredMethod() 获取私有成员,然后调用 setAccessible(true) 关闭 Java 的访问检查。

复制代码

Class<User> clazz = User.class; User user = new User(); Field field = clazz.getDeclaredField("name"); field.setAccessible(true); field.set(user, "张三"); Method method = clazz.getDeclaredMethod("sayHello"); method.setAccessible(true); method.invoke(user);

简单说,getDeclaredXxx() 可以获取本类中声明的私有成员,setAccessible(true) 让反射可以访问私有属性或方法

你前面提到了底层框架会用反射,那你说说++Spring,mybatis哪些地方用到了反射++?

Spring,mybatis哪些地方用到了反射?

Spring 中反射主要用在 Bean 的创建、属性注入、方法调用 上。

比如 Spring 根据类的 Class 对象,通过反射调用构造方法创建 Bean;然后通过反射给 @Autowired@Value 标注的字段或方法赋值;AOP、注解解析、生命周期方法调用也会用到反射。

MyBatis 中反射主要用在 对象映射 上,比如把数据库查询结果封装成 Java 对象时,会通过反射创建对象,并调用 setter 方法或直接给字段赋值。 简单说:Spring 用反射管理对象,MyBatis 用反射封装结果。

异常:

既然聊到了异常,请你说说 Error和Exception的区别,以及对应的有哪些异常/错误?

那请你说说你会怎么去进行处理?throw和throws的区别是什么?

Error和Exception的区别

ErrorException 都继承自 Throwable,但含义不一样。

Error 表示程序无法处理的严重问题 ,比如 OutOfMemoryError内存溢出、StackOverflowError栈溢出错误,一般不建议捕获。 Exception 表示程序可以处理的异常情况 ,比如空指针、IO 异常、数据库异常,通常需要通过 try-catch 或抛出处理。

简单说:Error 是系统级严重错误,Exception 是程序级异常。

常见的Error/Exception有哪些?

常见的 Error 有:

OutOfMemoryError:内存不足。 StackOverflowError:栈溢出,常见于递归太深。 NoClassDefFoundError:运行时找不到类。 ClassFormatError:类文件格式错误。

常见的 Exception 有:

NullPointerException:空指针异常。 ArrayIndexOutOfBoundsException:数组越界。 ClassCastException:类型转换异常。 NumberFormatException:数字格式转换异常。 IOException:IO 异常。 SQLException:数据库异常。

简单说:Error 偏 JVM 或系统级问题,Exception 偏代码运行中的可处理问题。

throw和throws的区别

throw 是在方法 内部主动抛出一个具体异常对象

复制代码

throw new RuntimeException("参数错误");

throws写在方法声明 上,表示这个方法可能会抛出某些异常,让调用者处理

复制代码

public void readFile() throws IOException { }

简单说:throw 是真正抛异常,throws 是声明 可能 抛异常。

除了throw抛出的异常,请你聊聊你对於++try-catch-finally的执行顺序的理解?++

try-catch-finally的执行顺序

try-catch-finally 的执行顺序是:先执行 try,如果 try 中出现异常,就执行对应的 catch,最后一定会执行 finally

如果 try 中没有异常,顺序就是:

复制代码

try → finally

如果 try 中有异常并被捕获,顺序就是:

复制代码

try → catch → finally

需要注意:finally 一般都会执行,常用于释放资源,比如关闭流、数据库连接等。只有极端情况,比如 System.exit() 或 JVM 崩溃,finally 才可能不执行。

finally中的代码一定会被执行吗?

不一定。

正常情况下,finally 基本都会执行,比如 try 中有 return、有异常,finally 也会先执行。

但有几种特殊情况不会执行,比如:

复制代码

System.exit(0);

或者 JVM 崩溃、线程被强制杀死、机器断电等。

所以面试里可以说:finally 通常一定执行,但不是绝对一定执行。

finally 块中如果有 return 语句,会发生什么?

如果 finally 块中有 return,它会覆盖 try 或 catch 中的 return 结果

比如:

复制代码

try { return 1; } finally { return 2; }

最终返回的是 2。所以实际开发中不建议在 finally 里写 return,因为它可能会吞掉异常或改变原本的返回结果,导致问题很难排查。

既然你都已经知道异常应该怎么去进行处理了,那++请你说一说不同的异常之间的区别?++

NoClassDefFoundError 和 ClassNotFoundException 的区别?

ClassNotFoundException受检异常 ,一般发生在程序通过反射或类加载器主动加载类时,比如:

复制代码

Class.forName("com.xxx.User");

如果类路径下找不到这个类,就会抛 ClassNotFoundException

NoClassDefFoundErrorError,通常是编译时类存在,但运行时类丢失、依赖缺失,导致 JVM 加载失败。

简单说:ClassNotFoundException 是主动加载找不到类;NoClassDefFoundError 是运行时依赖类缺失。

OutOfMemoryError 和 StackOverflowError 分别是什么原因导致的?

OutOfMemoryError堆内存 或方法区等 内存 不足导致的,比如创建了大量对象、集合一直增长、内存泄漏等。

StackOverflowError线程栈空间耗尽导致的,最常见原因是递归调用太深或者递归没有出口。

简单说:OOM 内存 不够用, StackOverflow 是方法 调用栈 太深。

相关推荐
过期动态2 小时前
【LeetCode 热题 100】盛最多水的容器
java·数据结构·spring boot·算法·leetcode·spring cloud·职场和发展
一 乐2 小时前
疫苗发布和接种预约|基于Java+vue疫苗发布和接种预约系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·疫苗发布和接种预约系统系统
2301_780789662 小时前
高防cdn如何缓存网页静态资源
java·spring·web安全·缓存·kubernetes·ddos
小马爱打代码2 小时前
Spring源码 第十一篇:Spring 扩展点全解析 - 从容器启动到 Bean 生命周期的完整执行时序
java·后端·spring
fantasy_arch3 小时前
BasicVSR-lite图像画质增强
开发语言·pytorch
甜味弥漫3 小时前
深度解析 JS 中的 this 指向:从底层逻辑到实战规则
javascript·面试
Rust语言中文社区3 小时前
【Rust日报】2026-05-24 Secluso v1.0.2 版本发布
开发语言·后端·rust
RainCity3 小时前
Java Swing 自定义组件库分享(九)
java·笔记·后端
li星野3 小时前
RAG优化系列:切块策略深度解析——固定长度 vs 自适应标题(含AI评估与面试指南)
人工智能·面试·职场和发展