【问题标题】:Java is backward compatible, but why we need to upgrade many libraries when we upgrade jdk from 1.6 to 1.8?Java是向后兼容的,但是为什么我们在将jdk从1.6升级到1.8的时候需要升级很多库呢?
【发布时间】:2015-03-29 11:45:03
【问题描述】:

最近,我们在我的一个 Java 项目中将 Jdk 版本从 1.6 升级到 1.8。但是有一些编译或运行时错误,所以我不得不升级一些库:

  • gradle: 1.91.10
  • 弹簧:3.x4.x

那是因为他们使用了一些早期版本的 ASM,但仅支持来自 5.x 的 jdk 1.8

Java说是向后兼容,但是为什么原版的库不能直接用jdk 1.8呢?

【问题讨论】:

  • Java 8 字节码不能在 Java 6 JVM 上运行——这不是向后兼容的意思。同理,Java 8 字节码也不能被专为 Java 6 字节码设计的库处理。
  • @LưuVĩnhPhúc 没有新的指令,但这并不意味着字节码格式没有改变(它已经改变了!)
  • 简而言之,ASM 库故意​​公开地不遵守代码必须满足的前提条件,以保证应用二进制兼容性。
  • @Lưu Vĩnh Phúc:这取决于您对口语术语“字节码”的含义。没有新的指令,但是类文件格式发生了变化。
  • @Rogério:取决于您对“类文件格式”的含义。总体结构没有改变,只有新版本号、新属性和关于允许/可能出现在哪些地方的构造的新定义。这足以使某些现有的字节码解析工具崩溃,这就是讨论的内容。附带说明一下,即使 javac 现在使用 invokedynamic 指令(这不是 Java 8 的新功能但在普通 Java 7 代码中未使用)这一事实,也会导致一些工具使用 Java 7 代码在 Java 8 代码上失败。

标签: java migration java-8 java-7


【解决方案1】:

ASM 是一个非常低级的库。

它直接处理 Java 字节码(而“普通”应用程序只会让 JVM 加载它的类)。字节码格式不时变化,较旧的JVM无法使用较新的版本。

向后兼容性不涵盖与 JDK 或类格式内部的混淆。

这确实是一个边缘案例,ASM 几乎是唯一“流行”的例子。


更重要(也更常见)的是系统库代码中的轻微行为变化。所以你的应用程序在技术上仍然可以运行,但做的事情不同。大多数时候,您希望这样做,因为这意味着改进(例如更好的性能),但有时它可能会给您带来错误。

例如:


但总而言之,旧版应用程序的兼容性故事对于 Java 来说非常好。他们必须牢记所有企业客户。

【讨论】:

【解决方案2】:

因为ASM 是一个对Java 字节码进行操作的工具。并且改变了字节码格式以引入新功能。因此,您必须升级工具以支持新的字节码。

请注意,使用较旧版本的 JDK 编译的软件并不总是适用于较新版本的 Java。例如,enum 在早期版本的 JDK 中不是关键字。

【讨论】:

  • 关于enum 关键字:这似乎只影响编译器。如果我用我自己的enum 类或字段或方法编译旧代码,它不应该仍然有效吗?如果我使用 new 关键字作为局部变量或参数名称,它肯定不会有任何效果。
  • @asteri:现在是关键字。在此之前,您可以将自己的事物(类、变量、方法)命名为enum。现在你不能了。结果,相同的代码不再使用新编译器编译(我仍然怀疑它会影响运行时)。
  • 当然可以。用-source 1.4 编译它。仍然在 Java7 上运行:public class enum{ public static void main(String[] argv){ System.out.println(1); } }
  • 您说“使用旧版本 JDK 编译的软件”,后来澄清说“因此在这种情况下使用 Java 1.4 编译的代码不适用于 Java 5+。”。当然,您不能再针对它正确编译,但它仍然可以运行。未更改的旧应用程序的二进制兼容性。
  • @Thilo 因代码违反合同而失败并不能算作二进制不兼容——代码的行为一开始是未定义。他们用UnsupportedOperationExceptionThread#stop(Throwable) 失败——我认为这是打破二进制兼容性的最有力的例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
相关资源
最近更新 更多