48

Java 版本之间是否存在不兼容性,其中针对 Java 版本 X 的 Java 源代码/Java 类文件不会在版本 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 的类不算作向后不兼容。
4

14 回答 14

24

各种版本的兼容性说明:

我记得的第一个重大问题是assertJava 1.4 的引入。它影响了很多 JUnit 代码

于 2009-10-31T17:36:00.500 回答
19

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

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

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

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

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

于 2009-10-31T17:10:59.043 回答
15

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

于 2009-10-31T17:07:50.323 回答
11

从 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,他们不太关心向后兼容性。例如,他们放弃了“私人保护”作为修饰语。

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

于 2009-11-01T00:11:26.417 回答
10

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

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

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

我记得在我从事的项目中引起问题的另一个问题是JInternalFrames 的默认可见性在 1.2 和 1.3 之间发生了变化。默认情况下它们是可见的,但是当我们升级到 1.3 时,它们似乎都消失了。

于 2009-10-31T17:51:58.520 回答
8

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

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

于 2009-10-31T17:37:44.180 回答
7

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

于 2009-10-31T17:05:32.777 回答
4

以下将在 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";
    }
}
于 2009-10-31T17:36:18.480 回答
4

显然,发布名称的命名约定不是向后兼容的

  • 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?

该列表来自维基百科。)

于 2009-10-31T18:39:41.527 回答
3

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对象”,但实际实现却另有说明。我的猜测是这是一个文档错误。

于 2009-10-31T17:57:40.370 回答
3

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

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

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

在此处输入图像描述

...

在此处输入图像描述

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

于 2011-01-07T10:16:08.370 回答
2

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

于 2009-10-31T17:25:42.597 回答
2

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

public class Test {
    float strictfp = 3.1415f;
}
于 2009-10-31T17:39:27.427 回答
1

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

于 2009-11-05T21:43:22.730 回答