当类在 Eclipse 中实现 Serialized 时,我有两个选择:添加默认值 serialVersionUID(1L) 或生成 serialVersionUID(3567653491060394677L). 。我认为第一个选项更酷,但很多时候我看到人们使用第二个选项。有什么理由产生 long serialVersionUID?

有帮助吗?

解决方案

据我所知,这只是为了与以前的版本兼容。仅当您之前忽略使用serialVersionUID,然后进行了您知道应该进行的更改时,这才有用 兼容的 但这会导致序列化中断。

请参阅 Java 序列化规范 更多细节。

其他提示

序列化版本 UID 的目的是跟踪类的不同版本,以便执行对象的有效序列化。

这个想法是生成一个对于某个类的特定版本唯一的 ID,然后当类中添加新的详细信息(例如新字段)时,该 ID 会发生更改,这会影响序列化对象的结构。

始终使用相同的 ID,例如 1L 意味着将来,如果类定义发生更改,从而导致序列化对象的结构发生更改,则在尝试反序列化对象时很可能会出现问题。

如果省略 ID,Java 实际上会根据对象的字段为您计算 ID,但我相信这是一个昂贵的过程,因此手动提供 ID 会提高性能。

以下是讨论类的序列化和版本控制的文章的几个链接:

生成的主要原因是使其与已经具有持久副本的类的现有版本兼容。

“长”默认值 serialVersionUID 是由定义的默认值 Java 序列化规范, ,根据默认序列化行为计算。

因此,如果您添加默认版本号,只要结构上没有任何更改,您的类就会更快地(反)序列化,但您必须注意,如果您更改类(添加/删除字段),您也会更新序列号。

如果您不必兼容现有的比特流,您可以将 1L 并在发生变化时根据需要增加版本。也就是说,更改后的类的默认序列化版本与旧类的默认版本不同。

每当您定义实施的类 java.io.Serializable. 。如果您不这样做,将为您自动创建一个,但这很糟糕。自动生成的serialVersionuID基于类的方法签名,因此,如果将来更改课程以添加方法(例如),则应使该类的“旧版本”的“旧版本”失败。这可能发生:

  1. 创建类的第一个版本,而无需定义serialversionuid。
  2. 将类的实例序列化到持久存储;序列化uID会自动为您生成。
  3. 修改您的类以添加新方法,然后重新部署您的应用程序。
  4. 试图在步骤2中逐步化序列化的实例,但现在失败(应该成功),因为它具有不同的自动生成的serialversionuid。

如果您没有指定serialVersionUID,那么Java 会即时创建一个。生成的serialVersionUID就是该数字。如果您更改类中的某些内容并没有真正使您的类与以前的序列化版本不兼容,而是更改了哈希值,那么您需要使用生成的非常大的数字serialVersionUID(或错误消息中的“预期”数字) 。否则,如果你自己记录一切,0、1、2...更好。

当您使用serialVersionUID(1L)而不是生成serialVersionUID(3567653491060394677L)时,您正在说些什么。

您是说,您 100% 确信没有任何系统会接触具有此类版本号为 1 的不兼容序列化版本的此类。

如果你能想到任何借口来解释它的序列化版本历史记录是未知的,那可能很难有信心地说。在它的生命周期中,一个成功的类将由许多人维护,存在于许多项目中,并驻留在许多系统中。

你可以为此苦恼。或者你也可以玩彩票希望输。如果您生成版本,则出现问题的可能性很小。如果你假设“嘿,我打赌还没人用过 1”,那么你的胜算就非常大了。正是因为我们都认为 0 和 1 很酷,所以你击中它们的几率更高。

-

当您生成serialVersionUID(3567653491060394677L)而不是使用serialVersionUID(1L)时,您正在说些什么。

你是说人们可能在这个类的历史上手动创建或生成了其他版本号,而你并不关心,因为长整型数字非常大。

无论哪种方式,除非您完全了解在该类已经存在或将永远存在的整个宇宙中序列化该类时所使用的版本号的历史记录,否则您就是在冒险。如果您有时间 100% 确定 1 是 AOK,那就去做吧。如果这需要大量工作,请继续盲目地生成数字。你中彩票的可能性比出错的可能性更大。如果是的话,请告诉我,我请你喝杯啤酒。

通过所有关于玩彩票的讨论,我可能给您留下了这样的印象:serialVersionUID 是随机生成的。事实上,只要数字范围均匀分布在 Long 的每个可能值上就可以了。然而,实际上是这样完成的:

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100

唯一的区别是你不需要随机源。您正在使用类本身的更改来更改结果。但根据鸽巢原理,仍然有可能出错并发生碰撞。这实在是太不可能了。祝我好运,从我身上得到一杯啤酒。

然而,即使该类只存在于一个系统和一个代码库中,认为手动增加数字使冲突的可能性为零就意味着您不理解人类。:)

好吧,serialVersionUID 是“静态字段不被序列化”规则的一个例外。ObjectOutputStream 每次将serialVersionUID 的值写入输出流。ObjectInputStream 读回它,如果从流中读取的值与当前版本的类中的serialVersionUID 值不一致,则会抛出 InvalidClassException。此外,如果要序列化的类中没有正式声明的serialVersionUID,编译器会自动添加根据类中声明的字段生成的值。

因为很多情况下默认的id并不是唯一的。所以我们创建 id 来制作独特的概念。

为了添加@David Schmitts 的答案,根据经验,我将始终使用默认的 1L 不符合惯例。我只需要返回并更改其中一些值几次,但当我进行更改并将默认数字每次更新为 1 时,我知道这一点。

在我目前的公司,他们需要自动生成的号码,因此我将其用于约定,但我更喜欢默认值。我的看法是,如果这不是您工作的约定,请使用默认值,除非您认为由于某种原因会不断更改序列化类的结构。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top