IllegalAccessException本质是JVM运行时拒绝反射访问,因目标成员不可见且未合法绕过权限检查:需setAccessible(true)但顺序/环境受限(如模块封禁、类加载器隔离、SecurityManager拦截等)。

IllegalAccessException 的本质,是 JVM 在反射调用时明确拒绝访问——不是代码写崩了,而是权限这道门被关死了。它不报编译错误,只在运行时甩出异常,常见于字段读写、方法调用或构造器实例化环节,核心就一条:目标成员对当前调用方不可见,且你没(或不能)合法打开它。
访问权限检查未绕过
Java 的 private、package-private(默认)成员天然屏蔽外部反射访问。哪怕你拿到了 Field 或 Method 对象,只要没调 setAccessible(true),JVM 就会拦下并抛出 IllegalAccessException。
- 典型场景:反序列化框架(如 Gson)尝试填充私有字段,但未主动设为可访问
- 注意:setAccessible(true) 是绕过 Java 语言层访问检查的开关,必须在 get() / invoke() 前调用,顺序错或漏掉都会触发异常
- 若类加载器不同(如插件系统中),即使 setAccessible(true) 成功,也可能因类隔离失败而抛此异常
模块系统封死反射通路
JDK 9 引入模块系统(JPMS)后,setAccessible(true) 不再万能。模块封装优先级高于反射权限控制,就算你开了“绿灯”,JVM 也可能根本不让你“看见”那个类。
将 WCAG 2 AA 无障碍标准应用于设计系统、UI 组件和网页——通过可运行的验证器进行对比度计算,采用设计 token 模式使颜色天生可访问,设定排版和焦点状态规则,并提供语义检查清单。适用于构建或审查 UI。
- 关键限制:目标包未在 module-info.java 中声明 opens(供反射)或 exports(供类型引用)
- 例如:com.example.internal 包未 opens 给 java.base,那么 Jackson 就无法反射访问其中的私有字段
- Java 16+ 默认启用 --illegal-access=deny,彻底禁用旧式反射穿透,此时 setAccessible(true) 直接抛 InaccessibleObjectException,而非 IllegalAccessException
安全与环境层面的硬拦截
某些运行环境会叠加额外限制,让反射访问从源头失效。
- SecurityManager(虽已弃用,但老容器或定制 JDK 仍可能启用)可策略性禁止 setAccessible 调用
- Android ART 运行时对隐藏 API(如 sun.*、jdk.* 内部类)有严格限制,反射访问会直接失败
- Spring Boot DevTools 热部署过程中类重载机制紊乱,可能导致同一类被多个类加载器加载,引发跨加载器访问异常
构造器私有导致实例化失败
反射创建对象时,如果目标类只有 private 构造器(比如单例、工具类),且未提前设为可访问,newInstance() 或 Constructor.invoke() 就会抛出 IllegalAccessException。
- 常见于测试代码中手动 new 某个本不该被外部实例化的类
- 解决方式不是改构造器为 public(破坏设计意图),而是先 getDeclaredConstructor(),再 setAccessible(true),再调用
- 若类无任何可见构造器(包括默认无参构造器被显式删除),则反射也无法补救,需确认是否误用










