IllegalAccessError 是 JVM 运行时错误,因编译期可见而运行时不可访问 package-private 成员所致,典型场景为跨类加载器或跨 JAR 的同名包中子类访问父类默认访问级别成员;修复推荐改为 protected 或确保同包同类加载器。

IllegalAccessError 是 JVM 在运行时抛出的错误(注意:是 Error,不是 Exception),表示某个类试图访问另一个类的成员(字段、方法、构造器等),但该成员在编译期可见、运行时却因类加载器隔离或访问修饰符限制而不可访问。其中一种典型场景是:**子类尝试访问父类中 package-private(即默认访问级别)的字段或方法,且二者不在同一包中**。
为什么会出现这个错误?关键在“编译期 vs 运行时”可见性差异
Java 编译器(javac)只检查源码层面的访问规则。如果子类和父类在同一个模块、同一源路径下编译,且父类字段是 package-private,而子类恰好也在同一包中——编译能通过。但若实际运行时,父类由一个类加载器(如系统类加载器)加载,子类由另一个类加载器(如自定义 ClassLoader 或模块系统隔离)加载,即使包名相同,JVM 也会视为“不同运行时包”,此时对 package-private 成员的访问会被拒绝,抛出 IllegalAccessError。
更常见的是:父类和子类虽在源码中同包,但被分别打包进不同 JAR,且未正确声明 module-info.java 或未配置 classpath/模块路径,导致运行时类加载器将它们视为不同命名空间。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
快速定位是否为 package-private 访问问题
- 查看异常堆栈,确认出错位置在子类中某行代码(如
super.fieldName或直接引用fieldName) - 检查该字段/方法在父类中的声明:无
public、protected、private修饰符 → 即为 package-private - 确认子类与父类是否真的在**同一个运行时包**:打印
ParentClass.class.getPackage()和ChildClass.class.getPackage(),对比getName()和getClassLoader() - 检查编译时 classpath 与运行时 classpath 是否一致;若用模块系统(Java 9+),确认
module-info.java中是否通过exports导出了父类所在包
修复方案:按场景选择合适方式
- 推荐:将父类成员改为 protected —— 若语义上允许子类继承访问,这是最直接、符合面向对象设计的方式。无需改动调用逻辑,兼容编译期和运行时
- 确保同包 + 同类加载器 —— 将父类和子类放在同一 Maven 模块或同一 JAR 中,并统一通过 classpath 加载(避免跨 JAR 的 package-private 引用)
-
模块化环境下显式导出 —— 若使用 Java 9+ 模块系统,在父类所在模块的
module-info.java中添加:
exports com.example.package.name;(必要时加上to other.module.name) -
避免直接访问,改用受保护的 getter/setter —— 在父类中提供
protected方法封装对 package-private 字段的操作,子类调用这些方法而非直接访问字段
调试小技巧:用 javap 辅助验证
执行 javap -private ParentClass 查看字节码中字段的实际修饰符;再执行 javap -private ChildClass 确认其是否生成了对父类 package-private 成员的直接符号引用(如 getfield 指令指向非 public 字段)。若存在,且运行时报 IllegalAccessError,基本可锁定为运行时包隔离问题。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










