【问题标题】:Are there any specific examples of backward incompatibilities between Java versions?Java 版本之间是否存在向后不兼容的具体示例?
【发布时间】:2010-12-11 21:55:15
【问题描述】:

Java 版本之间是否存在不兼容,Java 源代码/Java 类文件针对 Java 版本 X 无法在版本 Y(其中 Y > X)下编译/运行?

“Java 版本”是指以下版本:

  • JDK 1.0(1996 年 1 月)
  • JDK 1.1(1997 年 2 月)
  • J2SE 1.2(1998 年 12 月)
  • J2SE 1.3(2000 年 5 月)
  • J2SE 1.4(2002 年 2 月)
  • J2SE 5.0(2004 年 9 月)
  • Java SE 6(2006 年 12 月)

家规:

  • 请尽可能提供参考和代码示例。
  • 请尽量在您的回答中非常具体/具体。
  • 被标记为@Deprecated 的类不算作向后不兼容。

【问题讨论】:

  • 你的意思是'没有答案比一个过于模糊的答案更糟糕'
  • 这绝对应该是一个社区维基
  • 为什么?这是一个完全合法的技术问题......
  • Stephen C:我确实需要知道答案。
  • @Sean:需要知道这个答案的一个很好的理由是提倡选择 java 而不是 .NET 或 php 或用于某些给定项目的任何竞争技术,其中向后兼容性是必须。

标签: java jvm bytecode backwards-compatibility


【解决方案1】:

各种版本的兼容性说明:

我记得的第一个重大问题是在 Java 1.4 中引入了assert。 It affected a lot of JUnit code.

【讨论】:

  • 引入新的、保留的关键字要严惩!他们用枚举又做了一次。
  • 但他们从未将 goto 作为保留字删除!
  • 有趣的是,官方注释里面并没有对JDBC包不兼容的评论。还是我错过了?
  • @tangens - 可能没有注意到,因为 JDBC 客户端代码不需要更改以针对新 API 工作; Java 应用程序通常不会实现这些接口;数据库供应商会。您可以在 javadoc 中的 @since 标记中找到特定信息,并且可能在 JDBC 规范中有更多详细信息:java.sun.com/products/jdbc/download.html
【解决方案2】:

首先,Sun 实际上将您提到的所有版本(当然 1.0 除外)都视为次要版本,而不是主要版本。

我不知道当时有任何二进制不兼容的例子。但是,也有一些源不兼容的例子:

  • 在 Java 5 中,“enum”成为保留字;这不是以前。因此,有些源文件使用 enum 作为标识符,可以在 java 1.4 中编译而在 java 5.0 中无法编译。但是,您可以使用 -source 1.4 进行编译来解决这个问题。

  • 向接口添加方法也会破坏源代码兼容性。如果您实现了一个接口,然后尝试使用 JDK 编译该实现,该 JDK 将新方法添加到该接口,源文件将不再成功编译,因为它没有实现该接口的所有成员。这经常发生在 java.sql.Statement 和其他 jdbc 接口中。除非您实际调用不存在的方法之一,否则这些“无效”实现的编译形式仍然有效;如果这样做,将抛出 MissingMethodException。

这些是我能想到的几个例子,可能还有其他的。

【讨论】:

  • 最糟糕的部分是 JDBC 接口中添加的一些方法依赖于早期版本中不存在的新类型。这意味着不可能做出可以在多个 JDK 版本中编译的实现。
  • 我实际上在上周工作时又遇到了这个问题。我们最终求助于编写一个动态代理来获得一个可以在 Java 5 和 6 中编译的实现。
【解决方案3】:

接口 java.sql.Connection 从 Java 1.5 扩展到 Java 1.6,导致所有实现该接口的类的编译都失败。

【讨论】:

  • 我认为所有 JDBC 版本都广泛地做到了这一点。这应该不足为奇!
  • 再次使用 JDK 1.8。
【解决方案4】:

从 1.3 到 1.6,Swing 的每个版本都为我们打破了一些东西。

已经提到了 JDBC 问题,但是现有代码可以工作。

从 1.5 到 1.6,Socket 的行为发生了变化,破坏了 Cisco 客户端。

当然引入了新的保留关键字。

我认为对 Sun 而言真正不可原谅的一个大问题是 System.getenv()。它在 1.0 中工作,然后在 Mac 没有系统环境变量的相当可疑的理由下被弃用并更改为在所有平台上引发错误。然后 Mac 获得了系统环境变量,因此在 1.5 中它已被弃用并且可以正常工作。这样做没有合理的理由。在 Mac 上返回一个空集(如果您想关心跨平台一致性级别,Swing 的跨平台问题要大得多),甚至在所有平台上。

我从不同意他们关闭该功能,但将其更改为引发错误只是一个纯粹的破坏性更改,如果他们要这样做,他们应该完全删除该方法。

但是,实际上从 1.0 到 1.1,他们不太关心向后兼容性。例如,他们删除了“private protected”作为修饰符。

所以结果是每个版本都发生了足够的变化,需要仔细评估,这就是为什么你仍然在 SO 上看到许多 1.4 问题。

【讨论】:

    【解决方案5】:

    我能想到的主要是引入新的保留字:

    Java 1.3: strictfp
    Java 1.4: assert
    Java 5.0: enum
    

    以前使用这些值作为标识符的任何代码都不会在更高版本下编译。

    我记得在我从事的项目中引起问题的另一个问题是a change in the default visibility of JInternalFrames between 1.2 and 1.3。默认情况下它们是可见的,但是当我们升级到 1.3 时,它们似乎都消失了。

    【讨论】:

    • 如果他们保留一些将来可能会使用的关键字,即使不确定。 struct 和 function 之类的词目前是有效的标识符。
    【解决方案6】:

    在 1.3 和 1.4 之间,对 Long.parseLong(String) 的解释处理空字符串的方式不同。 1.3 返回一个 0 值,而 1.4 抛出一个 NumberFormatException。

    不需要重新编译,但如果工作代码依赖于 1.3 行为,它就会停止工作。

    【讨论】:

      【解决方案7】:

      memory modelchanged from 1.4 to 1.5 的语义。它已更改为允许除其他事项外再次双重检查锁定。 (我认为 volatile 语义是固定的。)它被破坏了。

      【讨论】:

      • 这是一个变化,但是 1.4 中的代码将如何中断到 1.5?似乎向后兼容我。
      【解决方案8】:

      以下将在 Java 1.4 下编译,但不是 Java 1.5 或更高版本。

      (Java 5 引入了 'enum' 作为关键字。注意:如果提供了“-source 1.4”选项,它将在 Java 5 中编译。)

      public class Example {
          public static void main(String[] args) {
              String enum = "hello";
          }
      }
      

      【讨论】:

        【解决方案9】:

        显然release names 的命名约定是not backwards-compatible。

        • JDK 1.0(1996 年 1 月 23 日)
        • JDK 1.1(1997 年 2 月 19 日)
        • J2SE 1.2(1998 年 12 月 8 日)
        • J2SE 1.3(2000 年 5 月 8 日)
        • J2SE 1.4(2002 年 2 月 6 日)
        • J2SE 5.0(2004 年 9 月 30 日)
        • Java SE 6(2006 年 12 月 11 日)
        • Java SE 6 更新 10、更新 12、更新 14、更新 16
        • Java SE 7 ??? JDK7?

        (The list is from Wikipedia.)

        【讨论】:

          【解决方案10】:

          又一个 java.sql 破坏兼容性的例子:

          在 1.5 中,将 compareTo(Date) 方法添加到 java.sql.Timestamp。如果提供的 Date 不是 java.sql.Timestamp 的实例,此方法将抛出 ClassCastException。当然,java.sql.Timestamp 扩展了 Date,并且 Date 已经有一个 compareTo(Date) 方法适用于所有 Dates,所以这意味着将 Timestamp 与(非时间戳)Date 进行比较的代码将在 1.5 运行时中断.

          有趣的是,1.6 似乎已经解决了这个问题。虽然 java.sql.Timestamp.compareTo(Date) 的文档仍然说“如果参数不是 Timestamp 对象,则此方法会抛出 ClassCastException 对象”,但实际实现却另有说明。我的猜测是这是一个文档错误。

          【讨论】:

            【解决方案11】:

            在此处查看有关 JRE 类库的 API 更改的报告:http://abi-laboratory.pro/java/tracker/timeline/jre/

            该报告包括 Java 类的向后二进制和源代码兼容性分析。

            报告由 japi-compliance-checker 工具生成。

            ...

            另一个关于 JDK 1.0-1.6 的有趣分析可以在 Japitools JDK-Results 页面找到。

            【讨论】:

              【解决方案12】:

              正如 Sean Reilly 所说,一种新方法可能会破坏您的代码。除了您必须实现一个新方法的简单情况(这将产生编译器警告)之外,还有一个最坏的情况:接口中的一个新方法与您已有的方法具有 same signature在你的课上。编译器的唯一提示是缺少 @Override 注释的警告(Java 5 用于类,Java 6 中的接口支持该注释,但可选)。

              【讨论】:

              • 解决方法:永远不要公开一个方法,除非它实现或覆盖了一个接口方法(不像听起来那么难——我已经坚持这个规则好几年了。)
              【解决方案13】:

              我还没有尝试过,但理论上这可以在 Java 1.1 中工作并在 Java 1.2 中中断。 (更多info here)

              public class Test {
                  float strictfp = 3.1415f;
              }
              

              【讨论】:

                【解决方案14】:

                根据个人经验,我们在 1.5 中将一些 AWT/Swing 文本字段嵌入到 SWT_AWT 框架中,升级到 1.6 后不再可编辑。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2015-02-11
                  • 2021-07-22
                  • 1970-01-01
                  • 2010-09-24
                  • 1970-01-01
                  • 2021-06-03
                  • 2021-12-25
                  • 1970-01-01
                  相关资源
                  最近更新 更多