我正在阅读Joshua Bloch撰写的Effective Java.
在第17项:"仅使用接口定义类型"中,我遇到了不建议使用接口存储常量的解释.我在下面解释.
"更糟糕的是,它代表了一种承诺:如果在将来的版本中修改了类以便它不再需要使用常量,它仍然必须实现接口以确保二进制兼容性."
二进制兼容性意味着什么?
有人可以用Java中的示例指导我,以显示代码是二进制兼容的.
Evg*_*eev 37
简而言之,二进制兼容性意味着当您更改类时,不需要重新编译使用它的类.例如,您从此类中删除或重命名了公共或受保护的方法
public class Logger implements Constants {
public Logger getLogger(String name) {
return LogManager.getLogger(name);
}
}
Run Code Online (Sandbox Code Playgroud)
从您的log-1.jar库中发布了一个新版本作为log-2.jar.当您的log-1.jar的用户下载新版本时,当他们尝试使用缺少的getLogger(String name)方法时,它将破坏他们的应用程序.
如果删除常量接口(第17项),由于相同的原因,这将破坏二进制兼容性.
但是,您可以删除/重命名此类的私有或包私有成员,而不会破坏二进制兼容性,因为外部应用程序不能(或不应该)使用它.
Cir*_*四事件 19
为了更好地理解这个概念,有趣的是,二进制兼容性并不意味着API兼容性,反之亦然.
API兼容但不兼容二进制:静态删除
图书馆版本1:
public class Lib {
public static final int i = 1;
}
Run Code Online (Sandbox Code Playgroud)
客户代码:
public class Main {
public static void main(String[] args) {
if ((new Lib()).i != 1) throw null;
}
}
Run Code Online (Sandbox Code Playgroud)
使用版本1编译客户端代码:
javac Main.java
Run Code Online (Sandbox Code Playgroud)
将版本1替换为版本2:删除static:
public class Lib {
public final int i = 1;
}
Run Code Online (Sandbox Code Playgroud)
仅重新编译版本2,而不是客户端代码,并运行java Main:
javac Lib.java
java Main
Run Code Online (Sandbox Code Playgroud)
我们得到:
Exception in thread "main" java.lang.IncompatibleClassChangeError: Expected static field Lib.i
at Main.main(Main.java:3)
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为即使我们可以用(new Lib()).iJava static和成员方法编写Java ,它也会根据以下内容编译为两个不同的VM指令Lib:getstatic或getfield.这个突破在JLS 7 13.4.10中提到:
如果未声明为private的字段未声明为static且更改为声明为static,反之亦然,则如果字段由预期存在的二进制文件使用,则会产生链接错误(特别是IncompatibleClassChangeError)另一种
我们需要重新编译Main与javac Main.java为它与新的版本.
笔记:
(new Lib()).i是坏样式,引发警告,永远不应该完成final原语是无用的:总是static final用于原语:private final static attribute vs private final attribute二进制兼容但不兼容API:null前置条件强化
版本1:
public class Lib {
/** o can be null */
public static void method(Object o) {
if (o != null) o.hashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
版本2:
public class Lib {
/** o cannot be null */
public static void method(Object o) {
o.hashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
客户:
public class Main {
public static void main(String[] args) {
Lib.method(null);
}
}
Run Code Online (Sandbox Code Playgroud)
这一次,即使Main在更新后重新编译Lib,第二次调用也将抛出,但不是第一次.
这是因为我们method以一种在Java编译时无法检查的方式改变了合同:在它可以采取之前null,之后不再这样做了.
笔记:
null价值观的API 是一个值得怀疑的做法二进制兼容性
Java的二进制兼容性规定了实施modication和类没有必要进一步阶级的重新编译重新编译导入 - 荷兰国际集团的modied类的条件.二进制兼容性是语言设计的新概念.
在Java语言specication [7]描述了如下二进制相兼容的变化:
如果先前存在的没有错误链接的预先存在的二进制文件将继续无错误地链接,则对类型的更改是二进制兼容的(等效地,不会破坏与预先存在的二进制文件的兼容性).
| 归档时间: |
|
| 查看次数: |
9478 次 |
| 最近记录: |