【问题标题】:why is not safe to rely on ObjectStreamClass.getSerialVersionUID?为什么依赖 ObjectStreamClass.getSerialVersionUID 不安全?
【发布时间】:2017-04-22 14:18:37
【问题描述】:

Java 规范说:“强烈建议所有可序列化类显式声明 serialVersionUID 值,因为默认的 serialVersionUID 计算对类细节高度敏感,可能会因编译器实现而异”

请问有人可以深入研究吗? getSerialVersionUID() 方法是做反射的,反射无处不在,那么依赖编译器呢?

【问题讨论】:

    标签: java reflection serialversionuid


    【解决方案1】:

    J. Bloch 的《Effective Java》一书对这个问题进行了精彩的解释:

    “第 74 条:明智地实现 Serializable”:

    如果您没有通过声明静态来明确指定此数字 final long 字段名为serialVersionUID,系统自动 通过对类应用复杂的过程在运行时生成它。 自动生成的值受类名的影响, 它实现的接口的名称,以及它的所有公共和 受保护的成员。如果你以任何方式改变这些东西,对于 例如,通过添加一个简单的方便方法,自动 生成的串行版本 UID 更改

    UPD:我还在评论中被问到,为什么它是编译器相关的。实际上,这里的编译器依赖性与getSerialVersionUID() 算法本身无关(当然,方法是在运行时调用的),而是与类本身的描述方式有关。例如,可以在编译时将一些合成方法添加到类中,这些方法也将计入 SUID。有关详细信息,请查看方法 ObjectStreamClass.computeDefaultSUID(),它的作用以及如何计算默认 SUID。

    【讨论】:

    • 但是这个解释并没有说明为什么依赖于编译器。是实时使用getSerialVersionUID()计算值吗?
    • @ejaenv,看看我的更新
    • 即使没有编译器依赖,当您更改static 字段或方法 时,您也不希望使用认为持久形式不兼容的算法。即使该类是否具有初始化程序也会产生影响。引文没有提到的是,不仅“它的所有公共和受保护成员”,而且所有包私有成员都被计算在内,这就是为什么像内部类访问器这样的合成方法很重要……
    • IMO computeDefaultSUID 应更改为有用的。
    • @ejaenv:好吧,更改算法会破坏与所有现有序列化数据的兼容性,并且还意味着使用新算法存储的数据将被旧 JRE 拒绝。
    猜你喜欢
    • 2015-11-15
    • 1970-01-01
    • 2017-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2019-10-27
    • 2021-09-01
    相关资源
    最近更新 更多