【发布时间】:2013-11-29 13:48:31
【问题描述】:
据我了解源代码兼容性以及如何轻松展示会破坏源代码兼容性的示例(更改方法名称、删除方法等),我在了解二进制兼容性如何在实践中被打破。有没有人有一个简单的例子来保持源代码兼容性,这会导致二进制兼容性问题,即不需要更改代码但需要重新编译?
【问题讨论】:
据我了解源代码兼容性以及如何轻松展示会破坏源代码兼容性的示例(更改方法名称、删除方法等),我在了解二进制兼容性如何在实践中被打破。有没有人有一个简单的例子来保持源代码兼容性,这会导致二进制兼容性问题,即不需要更改代码但需要重新编译?
【问题讨论】:
一个例子(这是 no 表示唯一的例子)是如果库中方法的签名以兼容的方式更改。例如,考虑:
// Library.java v1
public class Library {
public static void print(String foo) {
System.out.println(foo);
}
}
// Client.java v1
public class Client {
public static void main(String[] args) {
Library.print("hello");
}
}
编译运行:
$ javac Client.java Library.java
$ java Client
hello
现在更改 Library.java - 注意 foo 参数的类型:
// Library.java v2
public class Library {
public static void print(Object foo) {
System.out.println(foo);
}
}
只需重新编译Library.java 并尝试重新运行Client:
$ javac Library.java
$ java Client
Exception in thread "main" java.lang.NoSuchMethodError: Library.print(Ljava/lang/String;)V
at Client.main(Client.java:3)
【讨论】:
首先需要了解两者的兼容性。
源代码兼容性 - 如果程序可以使用新版本的代码(库或 api)编译,则程序与新版本的源代码兼容
二进制兼容性 - 如果程序无需重新编译即可与该代码链接,则程序与新版本代码二进制兼容
以下链接有更多关于“源兼容但二进制不兼容”的示例
阅读http://praitheesh.blogspot.com.au/2014/09/compatibility-and-api-evolution-in-java.html了解更多详情。
【讨论】:
如果您导入带有字符串常量的接口。 (Java 中的一种反模式。)
然后导入类复制常量表中的常量,并立即使用这些常量。接口的导入依赖就丢失了。
当接口中常量的字符串值发生变化时,编译器不会看到它需要重新编译仍使用旧值的类 - 因为不再有对接口的导入。
运行没有中断,但行为是-错误的值。
【讨论】:
我遇到的一个例子:
public class Class1 {
public void do() {
System.out.println("do!");
}
}
客户端部分:
public class Class2 {
public void callDo() {
Class1 c = new Class1();
c.do();
}
}
现在你改变 do 方法的返回:
public class Class1 {
public String do() {
System.out.println("do!");
return "done!";
}
}
如果您在没有重新编译的情况下运行客户端代码,您将收到 NoSuchMethodError 异常,因为方法签名已更改。
【讨论】: