Java版本之间是否存在向后不兼容的具体示例?

在Java版本中,Java版本X的Java源代码/ Java类文件不能在版本Y(Y> X)下编译/运行的Java发行版之间是否存在不兼容的问题?

“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的类不算作向后兼容性。

各种版本的兼容性说明:

  • Java 1.4
  • Java 5
  • Java 6
  • Java 7
  • Java 8

我记得的第一个主要问题是在Java 1.4中引入了assert 。 它影响了很多JUnit代码 。

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

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

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

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

这些是我可以从头顶回忆的几个例子,也可能有其他的例子。

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

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

JDBC问题已经被提到,但现有的代码工作。

从1.5到1.6,思科客户端的Socket行为发生了变化。

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

我认为在Sun的部分上真正不可原谅的是System.getenv()。 它工作在1.0,然后被弃用,并更改为在所有平台上的错误,在Mac没有系统环境variables的相当可疑的理由。 然后Mac得到系统环境variables,所以在1.5它不推荐和工作。 这样做没有合理的理由。 在Mac上返回一个空集(Swing有更大的跨平台问题,如果你想关心跨平台一致性的水平)甚至在所有平台上。

我从来没有同意他们closures这个function,但是改变它来抛出一个错误只是一个纯粹的破坏性的改变,如果他们要做的话,他们应该完全去掉这个方法。

但是,从1.0到1.1,他们不太关心向后兼容性。 例如,他们放弃了“私人保护”作为修改。

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

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

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

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

我记得另一个问题,导致我在一个项目上工作的问题是, JInternalFrames的默认可见性在1.2和1.3之间发生了变化 。 它们默认是可见的,但是当我们升级到1.3时,它们似乎都消失了。

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

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

内存模型的语义从1.4改为1.5 。 它被改变,允许除了其他事情再次检查锁再次。 (我认为易变的语义是固定的)它被打破了。

以下将在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"; } } 

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

  • 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 Update 10,Update 12,Update 14,Update 16
  • Java SE 7 JDK7?

( 这个清单来自Wikipedia 。)

又一个java.sql中断兼容性的例子:

在1.5中,compareTo(Date)方法被添加到java.sql.Timestamp。 如果提供的Date不是java.sql.Timestamp的实例,则此方法将抛出ClassCastException。 当然,java.sql.Timestamp扩展了Date,而且Date已经有了一个与所有date一起工作的compareTo(Date)方法,所以这意味着比较时间戳和(非时间戳)date的代码在运行时会在1.5 。

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

请参阅JRE类库的API更改报告: http : //abi-laboratory.pro/java/tracker/timeline/jre/

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

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

在这里输入图像说明

在这里输入图像说明

JDK 1.0-1.6的另一个有趣的分析,你可以在Japitools JDK-Results页面find。

正如肖恩·赖利所说,一种新的方法可能会破坏你的代码。 除了必须实现一个新方法(这会产生一个编译器警告)的简单情况之外,还有一个最坏的情况:接口中的一个新方法您在类中已有的方法具有相同的签名 。 编译器提示的唯一提示是缺less@Override注释(Java 5 for classes,注解支持Java 6中的接口,但是可选)。

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

 public class Test { float strictfp = 3.1415f; } 

从个人经验来看,我们在SWT_AWT框架中embedded了一些AWT / Swing文本字段,在升级到1.6后不再可编辑。