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

Java 8引入了重要的新语言function,如lambdaexpression式。

这些语言变化是否伴随着编译的字节码中的重大变化,如果不使用某些retrotranslator,将会阻止它在Java 7虚拟机上运行?

不,在您的源代码中使用1.8个function需要您定位1.8个虚拟机。 我刚刚尝试了新的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 

缺省方法需要对字节码和JVM进行这样的更改,而这些更改在Java 7上是不可能的.Java 7和以下版本的字节码validation器将拒绝接口与方法体(除了静态初始化方法)。 试图模拟调用方的静态方法的默认方法不会产生相同的结果,因为默认的方法可以在子类中重写。 Retrolambda对反向移植默认方法的支持有限,但它永远不能完全反向移植,因为它确实需要新的JVMfunction。

如果必要的API类在那里存在,Lambda可以运行在Java 7上。 invokedynamic指令存在于Java 7中,但是可以实现lambdaexpression式,以便在编译时生成lambda类(早期的JDK 8版本就是这样做的),在这种情况下,它可以在任何Java版本上运行。 (Oracle决定使用invokedynamic来进行lambdaexpression式的未来校对;也许有一天JVM将拥有一stream的函数,所以invokedynamic可以改为使用它们,而不是为每个lambda生成一个类,从而提高了性能。)Retrolambda做的是它处理所有这些invokedynamic指令并用匿名类replace它们; 就像Java 8在运行时第一次调用lamdba invokedynamic时所做的一样。

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

AFAIK, Type Annotations只在编译时才存在,所以它们不应该要求字节码的改变,所以只要改变Java 8编译类的字节码版本就足以使它们在Java 7上工作。

Java 7中的字节码中存在方法参数名称 ,因此也是兼容的。 您可以通过读取方法的字节码并查看方法的debugging信息中的局部variables名称来访问它们。 例如,Spring框架完全实现了@PathVariable ,所以可能有一个库方法可以调用。 由于抽象接口方法没有方法体,因此Java 7中的接口方法不存在debugging信息,在Java 8中也不存在AFAIK。

其他新function大多是新的API,对HotSpot和工具的改进。 一些新的API可用作第三方库(例如ThreeTen- Backport和streamsupport )。

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

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

也许下面的参考材料可以帮助我们加深对lambda相关变化的理解。

  • 从Lambdas到Bytecode
  • Lambdaexpression式的翻译

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

如果你愿意使用“retrotranslator”尝试Esko Luontola的优秀Retrolambda: https : //github.com/orfjackal/retrolambda

你可以执行-source 1.7 -target 1.7然后编译。 但是如果你有java 8的特定function(如lambdas),它将不能编译