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

Nic*_*tti 162 java compatibility jvm java-7 java-8

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

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

Jes*_*erE 143

不,在源代码中使用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
Run Code Online (Sandbox Code Playgroud)

  • 现在我明白了:你的"否"回答了问题的标题,而不是问题的正文. (5认同)
  • 不,我认为不会.Java占据了桌面市场的一小部分,但在紧紧抓住的情况下保持这一点.但它确实阻碍了新版本和功能的采用.我将无法在我编写的代码中使用Java 8功能很长一段时间,因为我想避免人们不得不升级本地Java安装. (4认同)

Esk*_*ola 57

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

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

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

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

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

其他新功能主要是新的API,HotSpot和工具的改进.一些新的API可用作第三方库(例如ThreeTen- Backportstreamsupport).

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

  • 实际上,类型注释可以是运行时可见的.http://stackoverflow.com/questions/22374612/is-it-possible-to-access-java-8-type-in​​formations-at-runtime (2认同)

Edw*_*rzo 33

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

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

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

  • 接口就是一个很好的例子.它们现在可以包含方法.Java7验证程序无法处理此问题.使用了所有旧的字节码,但是以一种新的方式. (12认同)
  • 没有新的字节码,但新的结构.验证者会呕吐. (7认同)
  • 我想知道具有如此多语言特性的scala编译器如何实现甚至jdk5的目标jvm版本。 (2认同)
  • @MarinosAn 你到底是什么意思?具有包含具体方法的特征的 MI,例如“类 C 用 B 扩展 A”,是通过普通接口“A”和“B”以及伴随类“A$class”和“B$class”实现的。类“C”只是将方法转发给静态伴生类。自类型根本不强制执行,lambda 在编译时被转译为抽象内部类,“new D with A with B”表达式也是如此。模式匹配是一堆 if-else 结构。非本地退货?来自 lambda 的 try-catch 机制。还剩下什么吗?(有趣的是,我的 scalac 说 1.6 是默认值) (2认同)

Ste*_*bel 11

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