zar*_*tra 15 java javac cross-compiling java-11
我正在开发一个小型库,出于明显的原因,我想使用所有Java 11功能(我现在猜不到的模块除外)来生成代码,但是我希望该库与Java 8及更高版本兼容。
当我尝试这个:
javac -source 11 -target 1.8 App.java
Run Code Online (Sandbox Code Playgroud)
我收到以下消息:
warning: source release 11 requires target release 11
Run Code Online (Sandbox Code Playgroud)
...当我查看字节码时,我看到该类的版本为0x37(Java 11):
$ xxd App.class
00000000: cafe babe 0000 0037 ...
Run Code Online (Sandbox Code Playgroud)
Java 8无法加载它:
Exception in thread "main" java.lang.UnsupportedClassVersionError: App has been
compiled by a more recent version of the Java Runtime (class file version 55.0),
this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
Run Code Online (Sandbox Code Playgroud)
人们如何提供这种兼容性?我对所有构建工具都开放。
对我来说,将高级语言(Java)转换为低级(字节码)似乎很容易。在我看来,当高级语言更改时,低级语言应保持不变。这就是为什么我认为这是可能的。
更新
伙计们,我认为这个答案不能与Move to OpenJDK-11相同,而是可以在Java 8中进行编译,因为OP询问如何继续生成具有Java 8功能的代码,但要针对Java 11(这是著名的向后兼容性)。我的问题是相反的:我想用Java 11生成代码,但要针对Java8。我在提出问题之前研究该主题时遇到了这个问题。我发现它不适用于我的情况。
另一个问题是否可以将Java 8代码编译为可在Java 7 JVM上运行,但确实与我的问题类似,但是在2013年有人问过,字节码显然在Java 7和Java 8之间发生了变化。
自Java 8以来,我认为字节码变化不大,这就是为什么我问这个问题。
Buu*_*man 12
不,您不能将 Java 11 源代码编译为 Java 8 二进制文件。
在javac方面,该-source参数不能超过更大的-target参数。
因此,如果您想生成 Java 8 二进制文件,您的源代码应该用 Java 8(或更早版本)编写。如果您不使用任何 Java 11 语言功能,那么您的源代码基本上已经在 Java 8 中,所以这应该不是什么大问题。
请注意,您仍然可以使用 JDK 11 将 Java 8 源代码编译为 Java 8 二进制文件。JDK 版本可以大于源和/或目标版本。
注意:javac 文档没有说明-source参数必须小于或等于-target参数。但是,有很多非官方文档。例如,
/sf/answers/648290891/
据我所知,实际上也没有一个反例可以让这种情况发挥作用。
尽管在javadoc的javadoc中没有看到任何明确的内容,但我认为您只能为-source和-target选项声明相同的版本。Java 8不支持Java 11功能,尽管情况恰恰相反,较高的Java版本可以运行在较低版本中编译的代码。因此,我认为不可能将编写为Java 11的代码编译为可在Java 8中运行。
虽然从理论上讲,使用复杂的工具可以将为JDK 11编译的类转换为JDK 8,但这并非微不足道。二进制级别有重大更改。
首先,JDK 11引入了嵌套类型,从而在访问private内部/外部类的成员时无需生成综合访问器方法。当然,在旧版本中,此类访问将失败。
它还引入了动态常量,尽管我不知道Java语言是否在任何地方都利用了该功能。这主要用于将来的版本。
然后,从JDK 9开始,使用Java 8中不存在的invokedynamic引用来编译字符串连接java.lang.invoke.StringConcatFactory。
可以使用的功能是private接口中的方法,它在Java 9中作为语言功能引入,但是已经在Java 8的二进制级别上进行了处理。
Java 8也将无法处理模块定义,但是我想,它们将被忽略。
我在这里可能是错的,但至少到目前为止,javac 并不打算以这种方式使用。
这里有点猜测:您可以尝试查看是否--release 8 --target 8有效(不提供--source 11参数)。
但我怀疑这会奏效。我认为 javac 不支持接受 N 源代码功能,并将其向后编译到早期目标版本。
当然,编译器可以了解将 N 个源代码转换为 (Nm) 个字节代码所需的转换。但这会使编译器变得更加复杂,并且每个版本都会增加这一点。它还会给测试工作增加巨大的成本。我怀疑编译器维护者是否愿意购买。这真的不是一个广泛的用例。
所以,我知道的唯一“解决方案”:分支和双重维护。为了让事情保持合理,我会简单地保留一个 Java 8 版本,也许是 Java 11 的一个版本。
| 归档时间: |
|
| 查看次数: |
4880 次 |
| 最近记录: |