为什么要生成long serialVersionUID而不是简单的1L?

时间:2009-05-20 14:37:44

标签: java serialization code-generation serialversionuid

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

11 个答案:

答案 0 :(得分:82)

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

有关详细信息,请参阅Java Serialization Spec

答案 1 :(得分:68)

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

我们的想法是生成一个特定版本的类所特有的ID,然后在添加到类中的新细节(例如新字段)时更改,这会影响序列化对象的结构

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

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

以下是一些文章的链接,这些文章讨论了类的序列化和版本控制:

答案 2 :(得分:17)

生成一个的主要原因是使它与已经存在副本的类的现有版本兼容。

答案 3 :(得分:13)

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

因此,如果您添加默认版本号,只要没有任何结构更改,您的类将(更少)序列化更快,但是如果您更改类(添加/删除字段),则必须注意还要更新序列号。

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

答案 4 :(得分:9)

每次定义时都应该创建一个serialVersionUID 实现java.io.Serializable的类。如果你不这样做,那就会 是自动创建的,但这很糟糕。自动生成 serialVersionUID基于您的类的方法签名,所以 如果您将来更改您的课程以添加方法(例如), 反序列化该类的“旧”版本将失败。这是什么 可能发生:

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

答案 5 :(得分:6)

如果你没有指定serialVersionUID,那么Java会动态生成一个。生成的serialVersionUID就是那个号码。如果您在类中更改某些内容并不会使您的类与以前的序列化版本不兼容但更改了哈希值,那么您需要使用生成的非常大数字的serialVersionUID(或错误消息中的“预期”数字) 。否则,如果你自己跟踪所有事情,0,1,2 ......就更好了。

答案 6 :(得分:4)

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

您所说的是,您完全相信没有任何系统能够触及此类具有此类的不兼容序列化版本且版本号为1的系统。

如果你能想到它的序列化版本历史未知的任何借口,那可能很难自信地说出来。在它的一生中,一个成功的课程将由许多人维护,住在许多项目中,并且驻留在许多系统中。

你可以为此烦恼。或者你可以玩彩票希望失败。如果你生成版本,你很可能会出错。如果你假设“嘿我打赌没有人用过1”你的赔率大于微小。正是因为我们都认为0和1很酷,你有更高的命中率。

-

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

你是说人们可能在本课程的历史记录中手动创建或生成了其他版本号,而你并不在意,因为Longs正在大肆宣传。

除非你完全知道在整个宇宙中序列化类所使用的版本号的历史,否则你将有机会。如果你有时间100%确定1是AOK,那就去吧。如果这需要很多工作,请继续并盲目地生成数字。你更有可能赢得彩票而不是出错。如果确实如此,请告诉我,我会给你买啤酒。

关于玩彩票的所有话题,我可能给你的印象是serialVersionUID是随机生成的。实际上只要数字范围均匀分布在Long的每个可能值上就可以了。但是,它实际上是这样做的:

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

你唯一的区别就是你不需要随机来源。您正在使用类本身的更改来更改结果。但根据鸽笼原则,它仍有可能出错并发生碰撞。这非常不可能。祝我喝啤酒好运。

然而,即使班级只会住在一个系统和一个代码库中,认为手动递增数字会让你没有碰撞的机会只意味着你不了解人类。 :)

答案 7 :(得分:1)

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

答案 8 :(得分:0)

因为在很多情况下,默认ID不是唯一的。所以我们创造了用于制作独特概念的id。

答案 9 :(得分:0)

要添加@David Schmitts答案,根据经验,我总是会使用默认的1L。我只需要返回并更改其中的一些,但我知道当我进行更改并每次更新默认数字时。

在我现在的公司,他们需要自动生成的号码,所以我将其用于惯例,但我更喜欢默认值。我的看法是,如果它不是你工作的约定,那么使用默认值,除非你认为你会因某种原因不断改变序列化类的结构。

答案 10 :(得分:0)

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

这个想法是生成一个类的特定版本所独有的ID,然后在类中添加了新细节(例如新字段)时更改该ID,这会影响序列化对象的结构

一个简单的解释:

您要序列化数据吗?

串行化基本上是将类数据写入文件/流/等。反序列化是将数据读回到类中。

您打算投产吗?

如果您仅使用不重要/伪造的数据进行测试,则不必担心(除非您直接测试序列化)。

这是第一个版本吗?

如果是这样,请设置serialVersionUID = 1L。

这是第二,第三等产品版本吗?

现在,您需要担心serialVersionUID,并应深入研究它。

基本上,如果在更新需要编写/读取的类时未正确更新版本,则在尝试读取旧数据时会出现错误。