URLClassLoader加载类时访问内部类触发IllegalAccessError的解决方法
问题分析
错误java.lang.IllegalAccessError的核心原因是:外部类myClass和内部类myClass$myInnerClass被不同的类加载器加载,且内部类默认是包访问权限。
在Java模块系统中,未命名模块(unnamed module)的包访问权限仅对同一类加载器加载的同包类开放。当myClass被URLClassLoader加载,而myClass$myInnerClass被应用类加载器(app loader)加载时,JVM会判定两者属于不同的运行时类,包级访问会被直接拒绝。
解决方案
1. 确保两类被同一个类加载器加载(推荐)
使用URLClassLoader加载myClass时,必须让该类加载器能定位到myClass$myInnerClass.class文件:
- 将包含这两个class文件的目录或JAR路径,添加到
URLClassLoader的构造参数中,确保类加载器可以找到内部类的字节码文件。 - 示例代码:
当外部类需要访问内部类时,会使用自身的类加载器去加载内部类,从根源上避免类加载器不一致的问题。// 假设class文件存放在./target/classes目录下 URL classDir = new File("./target/classes").toURI().toURL(); URLClassLoader customLoader = new URLClassLoader(new URL[]{classDir}); // 加载外部类,此时内部类会由同一个URLClassLoader加载 Class<?> myClass = customLoader.loadClass("myClass");
2. 修改内部类的访问权限
如果无法保证同一类加载器,可将内部类改为public,同时显式声明其构造方法为public(默认内部类构造方法为包级权限):
public class myClass { public class myInnerClass { // 显式声明public构造方法 public myInnerClass() {} } }
重新编译后,不同类加载器加载的类也能正常访问public权限的内部类。
3. 反射强制访问(应急方案)
若无法修改原代码,可通过反射绕过访问权限检查:
URLClassLoader customLoader = new URLClassLoader(new URL[]{classDir}); Class<?> outerClass = customLoader.loadClass("myClass"); // 实例化外部类 Object outerInstance = outerClass.getDeclaredConstructor().newInstance(); // 加载内部类 Class<?> innerClass = customLoader.loadClass("myClass$myInnerClass"); // 内部类构造方法默认需要传入外部类实例作为参数 Constructor<?> innerConstructor = innerClass.getDeclaredConstructor(outerClass); // 开启可访问性,绕过权限检查 innerConstructor.setAccessible(true); Object innerInstance = innerConstructor.newInstance(outerInstance);
内容的提问来源于stack exchange,提问作者HuyWallz
相关产品推荐
相关产品推荐

