为啥 Java 的基于值的类不应该被序列化?

Posted

技术标签:

【中文标题】为啥 Java 的基于值的类不应该被序列化?【英文标题】:Why should Java's value-based classes not be serialized?为什么 Java 的基于值的类不应该被序列化? 【发布时间】:2014-10-19 14:37:12 【问题描述】:

从版本 8 开始,Java 就有了value-based classes 的概念。这是为将来的版本做准备,该版本很可能允许定义value types。两个定义/描述都提到了序列化(我添加的粗体):

关于现有的基于值的类:

如果程序试图区分对基于值的类的相等值的两个引用,无论是直接通过引用相等还是间接通过诉诸同步、身份散列、序列化,它可能会产生不可预知的结果,或任何其他身份敏感机制。

关于未来值类型:

可通过 System.identityHashCode 获得的默认基于身份的对象哈希码也不适用于值类型。像 serialization 这样对对象进行基于身份的区分的内部操作要么不适用于值(因为它们不适用于原语),要么它们将使用值类型的 hashCode 提供的基于值的区分方法。

因为未来的 JVM 实现可能不会对基于值的类使用对象头和引用指针,所以一些限制是显而易见的。 (例如,不锁定 JVM 不得支持的标识。被锁定的引用可以在以后被删除并替换为另一个,这使得释放锁定毫无意义,并会导致死锁)。

但我不明白序列化如何发挥作用。为什么它被认为是一种“身份敏感机制”?为什么它“对对象进行基于身份的区分”

【问题讨论】:

实际问题和题目中的问题完全不同。 【参考方案1】:

序列化使用System.identityHashCode(通过IdentityHashMap)确保反序列化产生的对象图的拓扑在拓扑上与输入图的拓扑等效。

【讨论】:

这是我的观点——身份主要与图算法相关,以保留拓扑;即,避免循环循环。 这个答案只指出了为什么身份可能在反序列化过程中发挥作用。但是,我不明白为什么这意味着“基于值的类 [不应该] 被序列化”,这似乎是最初的问题。 (即使 OP 似乎对答案感到满意。) 有什么替代方法?我将如何序列化具有 localdate 字段的对象 另外,如果是这种情况,为什么要让 LocalDate Serializable? LocalDateTime为什么要实现Serializable?【参考方案2】:

想想当被序列化的对象图有一个循环时会发生什么。在这种情况下,序列化算法将进入无限循环——除非它具有检测和解决循环的特定机制。我们都知道Java的序列化允许循环对象图,所以机制是有的。

现在考虑循环的定义:图包含一个可从自身到达的对象。该定义指的是对象的身份,这意味着该机制必须考虑对象身份来跟踪周期。在实现层面,这是通过维护所有可见实例的IdentityHashMap 来实现的,并且该类依赖于Object.identityHashCode()

你引用的那句话解释了这个问题将如何在未来的 Java 版本中解决:值类型将被给予特殊处理,以便循环检测将依赖于它们自己的 equalshashCode 方法而不是 @987654325 @ 和identityHashCode

【讨论】:

以上是关于为啥 Java 的基于值的类不应该被序列化?的主要内容,如果未能解决你的问题,请参考以下文章

Java序列化-java.io.InvalidClassException本地类不兼容[重复]

javabean为啥要实现序列化

Java中为啥要序列化?啥时候用到序列化?

java.time和JPA

Java中为啥要序列化?啥时候用到序列化?

Java - InvalidClassException 本地类不兼容的serialVersionUID