简体   繁体   English

可以编译 Java 8 代码以在 Java 7 JVM 上运行吗?

[英]Can Java 8 code be compiled to run on Java 7 JVM?

Java 8 introduces important new language features such as lambda expressions. Java 8 引入了重要的新语言特性,例如 lambda 表达式。

Are these changes in the language accompanied by such significant changes in the compiled bytecode that would prevent it from being run on a Java 7 virtual machine without using some retrotranslator?语言中的这些变化是否伴随着编译后的字节码的如此重大变化,从而阻止它在不使用一些逆向翻译器的情况下在 Java 7 虚拟机上运行?

No, using 1.8 features in your source code requires you to target a 1.8 VM.不可以,在源代码中使用 1.8 功能需要以 1.8 虚拟机为目标。 I just tried the new Java 8 release and tried compiling with -target 1.7 -source 1.8 , and the compiler refuses:我刚刚尝试了新的 Java 8 版本并尝试使用-target 1.7 -source 1.8进行编译,但编译器拒绝:

$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8

Default methods require such changes to the bytecode and the JVM that they would have been impossible to do on Java 7. The bytecode verifier of Java 7 and below will reject interfaces with method bodies (except for the static initializer method).默认方法需要对字节码和 JVM 进行这样的更改,而它们在 Java 7 上是不可能做到的。Java 7 及以下版本的字节码验证器将拒绝与方法主体的接口(静态初始化方法除外)。 Trying to emulate default methods with static methods on the caller side would not produce the same results, because default methods can be overridden in subclasses.在调用方尝试使用静态方法模拟默认方法不会产生相同的结果,因为默认方法可以在子类中被覆盖。 Retrolambda has limited support for backporting default methods, but it can never be fully backported because it truly requires new JVM features. Retrolambda对向后移植默认方法的支持有限,但它永远无法完全向后移植,因为它确实需要新的 JVM 功能。

Lambdas could run on Java 7 as-is, if the necessary API classes just would exist there. Lambdas 可以按原样在 Java 7 上运行,前提是那里存在必要的 API 类。 The invokedynamic instruction exists on Java 7, but it would have been possible to implement lambdas so that it generates the lambda classes at compile time (early JDK 8 builds did it that way) in which case it would work on any Java version. invokedynamic 指令存在于 Java 7 上,但它本来可以实现 lambdas 以便它在编译时生成 lambda 类(早期的 JDK 8 构建就是这样做的),在这种情况下它可以在任何 Java 版本上运行。 (Oracle decided to use invokedynamic for lambdas for future proofing; maybe one day JVM will have first-class functions, so then invokedynamic can be changed to use them instead of generating a class for every lambda, thus improving performance.) What Retrolambda does is that it processes all those invokedynamic instructions and replaces them with anonymous classes; (Oracle 决定为 lambdas 使用 invokeDynamic 以供将来证明;也许有一天 JVM 将拥有一流的功能,因此可以更改 invokeDynamic 以使用它们,而不是为每个 lambda 生成一个类,从而提高性能。)Retrolambda 所做的是它处理所有这些调用动态指令并用匿名类替换它们; the same as what Java 8 does at runtime when a lamdba invokedynamic is called the first time.与 Java 8 在运行时第一次调用 lamdba 调用动态时所做的相同。

Repeating Annotations is just syntactic sugar. 重复注释只是语法糖。 They are bytecode compatible with previous versions.它们是与以前版本兼容的字节码。 In Java 7 you would just need to implement yourself the helper methods (eg getAnnotationsByType ) which hide the implementation detail of a container annotation which contains the repeated annotations.在 Java 7 中,您只需要自己实现辅助方法(例如getAnnotationsByType ),该方法隐藏包含重复注释的容器注释的实现细节。

AFAIK, Type Annotations only exist at compile time, so they should not require bytecode changes, so just changing the bytecode version number of the Java 8-compiled classes should be enough to make them work on Java 7. AFAIK, 类型注释只存在于编译时,所以它们不应该需要字节码更改,因此只需更改 Java 8 编译类的字节码版本号就足以使它们在 Java 7 上工作。

Method parameter names exist in the bytecode with Java 7, so that's also compatible. 方法参数名称存在于 Java 7 的字节码中,因此也是兼容的。 You can get access to them by reading the bytecode of the method and looking at the local variable names in the method's debug information.您可以通过读取方法的字节码并查看方法调试信息中的局部变量名称来访问它们。 For example the Spring Framework does exactly that to implement @PathVariable , so there is probably a library method which you could call.例如,Spring 框架正是为了实现@PathVariable ,所以可能有一个您可以调用的库方法。 Because abstract interface methods don't have a method body, that debug information doesn't exist for interface methods in Java 7, and AFAIK neither on Java 8.因为抽象接口方法没有方法体,所以 Java 7 中的接口方法不存在调试信息,Java 8 上的 AFAIK 也不存在。

The other new features are mostly new APIs, improvements to HotSpot and tooling. 其他新功能主要是新的 API、对 HotSpot 和工具的改进。 Some of the new APIs are available as 3rd party libraries (eg ThreeTen-Backport and streamsupport ).一些新 API 可作为 3rd 方库使用(例如ThreeTen- Backportstreamsupport )。

Summa summarum, default methods require new JVM features but the other language features don't. Summa summarum,默认方法需要新的 JVM 功能,但其他语言功能不需要。 If you want to use them, you'll need to compile the code in Java 8 and then transform the bytecode with Retrolambda to Java 5/6/7 format.如果要使用它们,则需要在 Java 8 中编译代码,然后使用Retrolambda将字节码转换为 Java 5/6/7 格式。 At minimum the bytecode version needs to be changed, and javac disallows -source 1.8 -target 1.7 so a retrotranslator is required.至少需要更改字节码版本,并且 javac 不允许-source 1.8 -target 1.7因此需要逆向翻译器。

As far as I know none of these changes in JDK 8 required the addition of new bytecodes.据我所知,JDK 8 中的这些更改都不需要添加新的字节码。 Part of the lambda instrumentation is being done using invokeDynamic (which already exist in JDK 7).部分 lambda 检测是使用invokeDynamic (已存在于 JDK 7 中)完成的。 So, from the JVM instruction set standpoint, nothing should make the codebase incompatible.因此,从 JVM 指令集的角度来看,不应使代码库不兼容。 There are, though, a lot of API associated and compiler improvements that would could make the code from JDK 8 difficult to compile/run under previous JDKs (but I have not tried this).但是,有许多相关的 API 和编译器改进可能会使 JDK 8 中的代码难以在以前的 JDK 下编译/运行(但我还没有尝试过)。

Maybe the following reference material can help somehow to enrich the understanding of how the changes related to lambda are being instrumented.也许以下参考资料可以以某种方式帮助丰富对如何检测与 lambda 相关的更改的理解。

These explain in detail how things are instrumented under hood.这些详细解释了如何在引擎盖下检测事物。 Perhaps you can find the answer to your questions there.也许您可以在那里找到问题的答案。

如果您愿意使用“retrotranslator”,请尝试 Esko Luontola 出色的 Retrolambda: https : //github.com/orfjackal/retrolambda

You can do -source 1.7 -target 1.7 then it will compile.你可以做-source 1.7 -target 1.7然后它会编译。 But it won't compile if you have java 8 specific features like lambdas但是如果你有像 lambdas 这样的 Java 8 特定功能,它就不会编译

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM