是否可以强制其他人的 java ClassLoader 加载包含有效 Java class 字节码的外部字节数组?

Is it possible to force someone else's java ClassLoader to load an external byte array containing the bytecode of a valid Java class?

我正在尝试强制系统 java class 加载程序(即 ClassLoader.getSystemClassLoader())加载由具有有效字节码的字节数组定义的外部 class 所以随后由此 classloader 加载的其他 classes 可以知道并实例化外部 class 而无需获得 NoClassDefFoundError.

这肯定行不通,因为它只在创建的 classloader 上定义了 class,而不是在系统 classloader:

URLClassLoader child = 
   new URLClassLoader(new URL[] { myJar.toURI().toURL()                          
   , ClassLoader.getSystemClassLoader());
Class.forName ("com.MyClass", true, child);

上面的代码将为子 classloader 定义 com.MyClass,而不是系统 classloader。

有什么方法可以做到吗?

您可以将反射与访问覆盖一起使用:

Method define = ClassLoader.class.getDeclaredMethod("defineClass",
                                      String.class, byte[].class, int.class, int.class);
define.setAccessible(true);
Class<?> clazz = (Class<?>)define.invoke(ClassLoader.getSystemClassLoader(),
                                      null, array, 0, array.length);

访问覆盖是必需的,因为我们正在调用 a protected method,但作为 protected 方法,它仍然是 API 的一部分,它存在于所有实现中并且不会'在未来的版本中不会消失。


Java 9 引入了一种惊人的简单方法,无需破解即可实现相同的效果,只要您自己的 class 也已通过应用程序 class 加载程序加载(以及是默认值):

Class<?> clazz = MethodHandles.lookup().defineClass(array);

这只是在与包含此语句的 class 相同的 class 加载上下文中创建 class。