反射调用不改变java代码块执行顺序规则,仅动态触发jvm规定的类初始化(父类静态→子类静态)和实例化(父类非静态→父构造→子类非静态→子构造)流程。

反射调用本身不改变 Java 原有的代码块执行顺序规则,它只是绕过编译期绑定,动态触发类加载和实例化过程——而这个过程严格遵循 JVM 规定的类初始化与对象构造顺序。
类加载阶段:静态代码块只执行一次
当通过 Class.forName("com.example.User") 或首次访问类的静态成员触发类加载时,JVM 会按以下顺序执行:
- 先加载该类及其父类(若未加载过)
- 对每个类,按声明顺序执行其 静态变量初始化 和 静态代码块
- 父类静态部分 → 子类静态部分,且每个类的静态内容仅执行一次
例如:Class.forName("Child") 会先执行 Parent 的静态块,再执行 Child 的静态块,之后整个类结构就“准备就绪”,后续反射操作不再重复触发。
对象创建阶段:构造代码块 + 构造器按序执行
调用 clazz.getDeclaredConstructor().newInstance() 或 constructor.newInstance(...) 时,实际等价于 new 操作,因此执行顺序与普通实例化完全一致:
- 先执行父类的非静态代码块(实例初始化块)
- 再执行父类构造器
- 然后执行子类的非静态代码块
- 最后执行子类构造器
注意:反射调用私有构造器前需调用 constructor.setAccessible(true),但这不影响执行顺序,只绕过访问检查。
方法调用阶段:不触发额外代码块
使用 method.invoke(obj, args) 调用任意方法(包括私有方法)时:
- 不会重新执行任何静态或非静态代码块
- 仅执行目标方法体内的逻辑
- 若方法内部新建对象,则新对象的构造流程照常触发对应代码块
也就是说,反射调用方法 ≠ 重新加载类或重建对象,它只是在已有实例上做方法分派。
关键提醒:顺序依赖类是否已初始化
反射行为是否触发代码块,取决于目标类是否已被 JVM 初始化:
-
String.class不会触发String类的静态块(它早已初始化) -
Class.forName("com.xxx.NewClass")会触发该类的静态初始化(前提是此前未加载) - 同一个类多次反射创建实例,每次都会执行非静态代码块和构造器
所以,代码块执行时机由 JVM 类加载机制决定,反射只是“启动”这个机制的其中一种方式,而非另起一套规则。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











