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则抛出一个NumberFormatException
exception。
重新编译是不需要的,但是如果工作代码依赖于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后不再可编辑。