如何在使用jdk8编译的jre9上运行代码并使用Unsafe

时间:2018-03-27 13:19:09

标签: java-9 backwards-compatibility unsafe

我有使用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下运行它。有可能吗?

2 个答案:

答案 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在评论中所说,明显的解决方案是重新编译

但如果你不能,如果你不反对丑陋的黑客,你可以:

  1. 获取sun.misc.Unsafe的来源并插入您需要/缺少的方法

  2. 创建一个自定义类加载器,它必须与系统类加载器一样,但是当请求加载sun.misc.Unsafe时,将加载你的Unsafe版本

  3. 使用自定义类加载器启动应用程序

    java -Djava.system.class.loader = com.xxx.MyCustomClassLoader xxx

  4. 丑陋但可以在不重新编译的情况下工作