首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用Java 11编写代码,但目标是Java 8和更高版本?

如何用Java 11编写代码,但目标是Java 8和更高版本?
EN

Stack Overflow用户
提问于 2019-01-30 18:49:31
回答 5查看 45.7K关注 0票数 60

我正在开发一个小型库,出于明显的原因,我想使用所有Java 11特性编写代码(除了目前估计的模块外),但我希望这个库与Java 8及更高版本兼容。

当我尝试这个:

代码语言:javascript
复制
javac -source 11 -target 1.8 App.java

我收到以下信息:

代码语言:javascript
复制
warning: source release 11 requires target release 11

...and当我查看字节码时,我看到类的版本是0x37 (Java11):

代码语言:javascript
复制
$ xxd App.class
00000000: cafe babe 0000 0037 ...

Java 8无法加载它:

代码语言:javascript
复制
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)

人们是如何提供这种兼容性的?我对所有的构建工具开放。

对我来说,将高级语言(Java)转换为低级(字节码)似乎很容易。在我看来,当高级语言发生变化时,低层语言应该保持不变。这就是为什么我认为这是可能的。

更新

伙计们,我不认为这个答案重复了转到OpenJDK-11,但在Java 8中编译,因为OP询问如何继续生成带有Java 8特性的代码,但是目标是Java11(这只是一个著名的向后兼容性)。我的问题是相反的:我想用Java 11生成代码,但目标是Java 8。在提出问题之前,我在研究这个主题时遇到了这个问题。我觉得它不适合我的情况。

另一个问题可以编译Java 8代码在Java 7 JVM上运行吗?看起来确实与我的问题类似,但它是在2013年提出的,字节码在Java7和Java8之间显然发生了变化。

我认为自Java 8以来字节码并没有发生太大的变化,这就是我问这个问题的原因。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-05-09 17:16:42

虽然为JDK 11编译的类到JDK 8的转换理论上可以用一个复杂的工具实现,但这并不简单。二进制级别有很大的变化。

首先,JDK 11引入了嵌套类型,它无需在访问内部/外部类的private成员时生成合成访问器方法。当然,这种访问在旧版本中会失败。

它还引入了动态常数,尽管我不知道Java是否在任何地方利用了这个特性。这主要是为了将来的版本。

然后,从JDK 9开始,使用invokedynamic编译字符串连接,引用Java8中不存在的java.lang.invoke.StringConcatFactory

一个可以工作的特性是接口中的private方法,它作为一种语言特性引入Java 9中,但在Java8中已经在二进制级别上进行了处理。

Java 8也无法处理模块定义,但我认为它们将被忽略。

票数 27
EN

Stack Overflow用户

发布于 2019-05-09 05:55:22

不,不能将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参数。不过,这里有很多非官方文件。例如,https://stackoverflow.com/a/9261298/691074

据我所知,也没有一个反例能让这种情况真正发挥作用。

票数 21
EN

Stack Overflow用户

发布于 2020-02-06 03:47:03

有一个名为贾贝尔的工具是由@bsideup创建的,它允许您这样做。它伪装成一个注释处理器,这样就可以插入javac。但是,它不进行任何实际的注释处理。相反,在编译过程中,它会侵入javac内部,并使它相信变量、匿名类创建中的菱形以及文本块开关表达式等较新的特性都可以在Java8中使用。

这是无任何保证的黑客解决方案,所以请小心使用。

票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54447541

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档