有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使反射在JDK 16及更高版本上工作?

我有以下迁移到Java 16的遗留代码,但由于这个新版本引入了强大的封装,它无法工作:

try {
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
    method.setAccessible(true);
    method.invoke(new URLClassLoader(
        new URL[] {}),
        new File("C:/external-folder/my.jar").toURI().toURL()
    );
} catch (Exception exc) {
    exc.printStackTrace();
}

有没有办法让它发挥作用


共 (2) 个答案

  1. # 1 楼答案

    代码很奇怪。乍一看,我认为它使用反射来访问URLClassLoader内部,将myJar添加到现有的类加载器,但它使用反射将其添加到新的类加载器。没有理由这么做-你可以用the ^{} constructor来做

    它应该是这样的(未经测试,因为我远离IDE):

    URL jar = new File("C:/external-folder/my.jar").toURI().toURL();
    URL[] urls = { jar };
    new URLClassLoader(urls);
    
  2. # 2 楼答案

    问题不在于反射“不起作用”;正是反射最终强制执行了编译器和运行时一直强制执行的更多可访问性模型URLClassLoader::addUrl仅用于子类;它不打算从实现外部访问,这正是您正在做的。随着时间的推移,从Java9开始,到后来的版本(包括17),访问限制越来越多地被反射识别出来,并发出警告,使损坏的代码有机会迁移到可支持的地方

    所讨论的代码只在意外情况下工作过;这取决于能否进入不受支持的接口。使用setAccessible应该是一个线索。当然,你可以打破窗户进入锁着的房子,但是如果你必须打破窗户(而不是你的房子),你应该知道问题出在哪里

    把它看成是半满的杯子;这个意外工作的代码工作了很长时间。但是账单已经到期了;现在是修复代码的时候了