我有使用jdk8编译的代码作为java 1.8的目标和源代码并使用Unsafe。我试图用jdk9运行这个程序,但它失败了以下异常:
java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte
包sun.misc.Unsafe没有从jdk9中删除,所以我希望代码能够运行。我不能用jdk9重新编译代码,我期望java应该向后兼容。
我创造了一些对我不起作用的测试。 考试类:
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class Test {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
System.out.println("before");
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafeField.get(null);
unsafe.getByte(new Object(), 4);
System.out.println("after");
}
}
然后我用jdk8编译代码。
C:\Java-IDE\jdk1.8.0_121\bin\javac.exe Test.java
然后,如果我用jdk8运行它,它可以工作:
C:\Java-IDE\jdk1.8.0_121\bin\java.exe Test
before
after
如果我用jdk9运行它会抛出异常:
C:\Java-IDE\jdk-9.0.4_windows-x64_bin\bin\java.exe Test
before
Exception in thread "main" java.lang.NoSuchMethodError: sun.misc.Unsafe.getByte(Ljava/lang/Object;I)B
at Test.main(Test.java:13)
我相信也应该可以在jdk9下运行它。有可能吗?
答案 0 :(得分:2)
方法byte Unsafe.getByte(Object, int)
已在Java 9中删除,但重新编译修复了该问题,因为它将导致byte Unsafe.getByte(Object, long)
的调用,这确实是预期的替代。
请注意,即使Unsafe
是应用程序不应使用的非官方,不受支持的API这一事实,使用int
偏移的方法也不推荐使用long
的方法从1.4.1
开始,这意味着有一年半的时间来调整旧代码,但是你的代码“用jdk8编译为目标”的说法表明它实际上甚至更年轻。
鉴于已经多次宣布计划完全删除sun.misc.Unsafe
,如果代码将在未来的JVM版本上运行,则无法更改代码。如果您无法重新编译它,请问自己,将来无法重新编译的代码的维护应该如何。如果代码应该被冻结,也要冻结JVM版本。否则,您需要找到重新编译或替换它的方法。
答案 1 :(得分:-1)
是java是向后兼容的,但它适用于java API。 sun.misc包是Sun / Oracle公布的可移动/可更新/删除的软件包之一,没有任何预先警告。
所以它是
要回答您的问题,您需要更新代码
编辑:
就像Alan Bateman在评论中所说,明显的解决方案是重新编译
但如果你不能,如果你不反对丑陋的黑客,你可以:
获取sun.misc.Unsafe的来源并插入您需要/缺少的方法
创建一个自定义类加载器,它必须与系统类加载器一样,但是当请求加载sun.misc.Unsafe时,将加载你的Unsafe版本
使用自定义类加载器启动应用程序
java -Djava.system.class.loader = com.xxx.MyCustomClassLoader xxx
丑陋但可以在不重新编译的情况下工作