【发布时间】:2017-04-22 14:18:37
【问题描述】:
Java 规范说:“强烈建议所有可序列化类显式声明 serialVersionUID 值,因为默认的 serialVersionUID 计算对类细节高度敏感,可能会因编译器实现而异”
请问有人可以深入研究吗? getSerialVersionUID() 方法是做反射的,反射无处不在,那么依赖编译器呢?
【问题讨论】:
标签: java reflection serialversionuid
Java 规范说:“强烈建议所有可序列化类显式声明 serialVersionUID 值,因为默认的 serialVersionUID 计算对类细节高度敏感,可能会因编译器实现而异”
请问有人可以深入研究吗? getSerialVersionUID() 方法是做反射的,反射无处不在,那么依赖编译器呢?
【问题讨论】:
标签: java reflection serialversionuid
J. Bloch 的《Effective Java》一书对这个问题进行了精彩的解释:
“第 74 条:明智地实现 Serializable”:
如果您没有通过声明静态来明确指定此数字 final long 字段名为serialVersionUID,系统自动 通过对类应用复杂的过程在运行时生成它。 自动生成的值受类名的影响, 它实现的接口的名称,以及它的所有公共和 受保护的成员。如果你以任何方式改变这些东西,对于 例如,通过添加一个简单的方便方法,自动 生成的串行版本 UID 更改
UPD:我还在评论中被问到,为什么它是编译器相关的。实际上,这里的编译器依赖性与getSerialVersionUID() 算法本身无关(当然,方法是在运行时调用的),而是与类本身的描述方式有关。例如,可以在编译时将一些合成方法添加到类中,这些方法也将计入 SUID。有关详细信息,请查看方法 ObjectStreamClass.computeDefaultSUID(),它的作用以及如何计算默认 SUID。
【讨论】:
static 字段或方法 时,您也不希望使用认为持久形式不兼容的算法。即使该类是否具有初始化程序也会产生影响。引文没有提到的是,不仅“它的所有公共和受保护成员”,而且所有包私有成员都被计算在内,这就是为什么像内部类访问器这样的合成方法很重要……