显式serialVersionUID被认为有害吗?

我可能会冒这个问题冒险。

在我看来,为新类明确指定serialVersionUID是不好的。 考虑两种情况,即在布局应该更改时不更改它,并在不应该更改时更改它。

几乎只有在明确的情况下才会发生变化。 在这种情况下,它会导致一些非常微妙,难以发现的错误。 特别是在开发过程中,类布局经常变化。 但是如果它没有明确指定,它将会改变并且反序列化将大声破坏,最有可能通过清除存储库来解决。

不应该发生的情况几乎只有在隐含时才会发生。 这是一种罕见的情况,其中类布局已更改但我们仍希望从旧的序列化blob反序列化。 这可能会在QA期间被捕获( 从5.2升级到5.2.1之后的奇怪错误,请参阅附加的堆栈跟踪 ),并且可以通过设置显式值来轻松修复。

注释?

由于类布局更改以外的原因,更改何时不应该发生 – 问题在于它依赖于编译器实现。 如果您使用Eclipse进行调试但使用javac进行生产构建, 最终可能会出现两个不兼容的数据集。

在我的工作中,我们明确禁止指定serialVersionUID,正是因为你提出的问题。

另外,我们持久化的类仅用于存储内部没有逻辑的数据,因此它们改变的唯一方法是更改​​数据成员。

进一步强调约翰双向飞碟说的话并与评论相矛盾:

“如果你不需要它(即你总是使用相同的类版本序列化和反序列化),那么你可以安全地跳过显式声明”

即使您没有长期序列化并使用相同的类版本, 您仍然可能会遇到问题 。 如果您正在编写客户端 – 服务器代码,并且客户端代码可以运行与服务器不同的jvm版本/实现,那么您可能会遇到与不兼容的serialversionuids相同的问题。

总而言之, 唯一一次不指定serialversionuids是“安全”的是当你没有长期序列化时,你保证序列化数据的所有使用者将使用与原始生产者相同的jvm实现和版本。

总之, 使用serialversionuid通常是更有害的情况。

当您需要通过序列化支持长时间持久性时,您几乎总是需要使用自定义代码来支持这一点,并且需要显式设置serialVersionUID ,否则较旧的序列化版本将无法通过较新的代码进行反序列化。

这些场景已经需要非常小心,以便在类更改时使所有案例都正确,因此serialVersionUID是您遇到的最少问题。

如果您不需要它(即您始终使用相同的类版本进行序列化和反序列化),则可以安全地跳过显式声明,因为计算出的值将确保使用正确的版本。

无论你是否使用serialVersionUID (我建议你这样做),那么你应该考虑为串行兼容性创建一套全面的测试。

值得设计串行格式也值得。 它实际上是一个公共API。

如果您只是使用序列化进行远程方法调用,例如调用EJB,其中客户端和服务器类以及jvm是相同的,我怀疑这是最常用的,然后显式设置serialVersionUID(例如eclipse)因为固定的serialVersionUID,不兼容的类实例被视为兼容的偶然的,无法解释的错误forms可能会导致你的重大痛苦。 在低级别序列化期间,远程调用将无声地出错,并且只有在对象的状态不一致时才会出现问题。 只有当您意识到客户端和服务器类在某种程度上不同时才能找到问题的根源(尽管serialVersionUID当然不是)。 根据我的经验,为此设置serialVersionUID弊大于利。

另一方面,如果您明确地将serialVersionUID设置为读入旧数据,则根据定义,您将读取不兼容的版本,并且最终可能会出现处于不一致或不完整状态的对象。 在这种情况下,设置serialVersionUID是针对不同问题的解决方法。