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

时间:2013-04-22 09:29:25

标签: java jvm compatibility java-7 java-8

Java 8引入了重要的新语言功能,例如lambda表达式。

语言中的这些更改是否伴随着编译的字节码中的这些重大更改,这些更改会阻止它在不使用某些反向转换器的情况下在Java 7虚拟机上运行?

5 个答案:

答案 0 :(得分:130)

不,使用源代码中的1.8功能要求您定位1.8 VM。我刚刚尝试了新的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

答案 1 :(得分:55)

默认方法需要对字节码和JVM进行此类更改,而这些更改在Java 7中是不可能的.Java 7及更低版本的字节码验证程序将拒绝具有方法主体的接口(静态初始化方法除外)。尝试使用调用方的静态方法模拟默认方法不会产生相同的结果,因为可以在子类中重写默认方法。 Retrolambda对反向移植默认方法的支持有限,但它永远不能完全向后移植,因为它确实需要新的JVM功能。

Lambda可以在Java 7上运行,如果那里存在必要的API类。 invokedynamic指令存在于Java 7上,但是它可以实现lambdas,以便它在编译时生成lambda类(早期的JDK 8版本就是这样做的),在这种情况下它可以在任何Java版本上运行。 (Oracle决定使用invokedynamic for lambdas进行未来验证;也许有一天JVM将拥有一流的功能,因此可以更改invokedynamic以使用它们而不是为每个lambda生成一个类,从而提高性能。)Retrolambda所做的是它处理所有这些invokedynamic指令并用匿名类替换它们;与第一次调用lamdba invokedynamic时Java 8在运行时所做的相同。

Repeating Annotations只是语法糖。它们与先前版本的字节码兼容。在Java 7中,您只需要自己实现辅助方法(例如getAnnotationsByType),它隐藏包含重复注释的容器注释的实现细节。

AFAIK,Type Annotations仅在编译时存在,因此它们不应该要求更改字节码,因此只需更改Java 8编译类的字节码版本号就足以使它们在Java 7上工作。 / p>

Method parameter names存在于Java 7的字节码中,因此它也是兼容的。您可以通过读取方法的字节码并查看方法调试信息中的局部变量名来访问它们。例如,Spring Framework正是为了实现@PathVariable,所以可能有一个库方法可以调用。因为抽象接口方法没有方法体,所以Java 7中的接口方法和Java 8上的接口方法都不存在调试信息。

The other new features主要是新的API,对HotSpot和工具的改进。某些新API可用作第三方库(例如ThreeTen-Backportstreamsupport)。

Summa summarum,默认方法需要新的JVM功能,但其他语言功能不需要。如果要使用它们,则需要在Java 8中编译代码,然后将字节码转换为Retrolambda到Java 5/6/7格式。至少需要更改字节码版本,并且javac不允许-source 1.8 -target 1.7,因此需要使用逆向转换器。

答案 2 :(得分:31)

据我所知,JDK 8中的这些更改都不需要添加新的字节码。 lambda检测的一部分是使用invokeDynamic(已经存在于JDK 7中)完成的。因此,从JVM指令集的角度来看,没有任何东西可以使代码库不兼容。但是,有很多API关联和编译器改进可能会使JDK 8中的代码难以在以前的JDK下编译/运行(但我没有尝试过)。

也许以下参考资料可以帮助以某种方式丰富对如何修改与lambda相关的变化的理解。

这些详细解释了如何在引擎盖下进行检测。也许你可以在那里找到问题的答案。

答案 3 :(得分:11)

如果您愿意使用“逆转译器”,请尝试Esko Luontola优秀的Retrolambda:https://github.com/orfjackal/retrolambda

答案 4 :(得分:-5)

你可以-source 1.7 -target 1.7然后编译。但是如果你有像lambdas这样的java 8特定功能

,它就不会编译