为什么生成long serialVersionUID而不是简单的1L?
当类在Eclipse中实现Serializable时,我有两个select:添加默认serialVersionUID(1L)
或生成serialVersionUID(3567653491060394677L)
。 我认为,第一个更酷,但很多时候我看到有人使用第二个选项。 是否有任何理由生成long serialVersionUID
?
据我所知,这只是为了与以前的版本兼容。 如果你之前忽略使用serialVersionUID,那么这将是有用的,然后做出一个你知道应该兼容但是会导致序列化中断的改变。
有关更多详细信息,请参阅Java序列化规范 。
序列化版本UID的目的是跟踪不同版本的类,以便执行对象的有效序列化。
这个想法是生成一个对某个特定版本的类是唯一的ID,当有新的细节添加到类,如一个新的领域,这将影响序列化的对象的结构,然后更改。
总是使用相同的ID,例如1L
意味着将来如果类定义被改变,导致序列化对象的结构发生变化,那么尝试反序列化对象时就会出现问题。
如果省略ID,Java实际上会根据对象的字段为您计算ID,但我相信这是一个昂贵的过程,所以手动提供一个将提高性能。
以下是几篇讨论序列化和版本化的文章的链接:
- JDC技术提示:2000年2月29日 (链接截至2013年2月)
- 发现Java序列化API的秘密
生成的主要原因是使它与现有版本的已经存在持续副本的类兼容。
serialVersionUID
的“long”默认值是Java序列化规范定义的默认值,由默认序列化行为计算。
所以如果你添加默认的版本号,只要没有任何结构改变,你的类就会(更快)序列化,但是如果你改变类(添加/删除字段),你必须小心,序列号。
如果您不必与现有的比特stream兼容,则可以将1L
放在那里,并在发生变化时根据需要增加版本。 也就是说,当更改的类的默认序列化版本与旧类的默认版本不同时。
每当你定义一个实现了java.io.Serializable
的类时,你绝对应该创build一个serialVersionUID。 如果你不这样做,会自动创build一个,但这是不好的。 自动生成的serialVersionUID基于你的类的方法签名,所以如果你将来改变你的类来添加一个方法(例如),反序列化类的“旧”版本将失败。 以下是可能发生的情况:
- 创build你的类的第一个版本,而不需要定义serialVersionUID。
- 将你的类的一个实例序列化到一个持久存储中; serialVersionUID会自动为您生成。
- 修改你的类来添加一个新的方法,并重新部署你的应用程序。
- 尝试反序列化在第2步中序列化的实例,但现在失败(应成功),因为它具有不同的自动生成的serialVersionUID。
如果你没有指定一个serialVersionUID,那么Java会立即执行。 生成的serialVersionUID就是这个数字。 如果你在你的类中改变了一些并不能使你的类与之前的序列化verisons不兼容但改变hash的东西,那么你需要使用生成的非常大的serialVersionUID(或者错误消息中的“expected”号码) 。 否则,如果你正在跟踪自己的一切,0,1,2 …更好。
当您使用serialVersionUID(1L)而不是生成serialVersionUID(3567653491060394677L)时,您正在说些什么。
你的意思是,你百分之百地确信,没有一个系统会碰到这个类,它有一个版本号为1的这个类的不兼容的序列化版本。
如果你可以想象任何借口,因为它的序列化版本历史是未知的,这可能很难说有信心。 一生中,一个成功的class级将由许多人维护,生活在许多项目中,并驻留在许多系统中。
你可以为此苦恼。 或者你可以玩彩票希望失去。 如果你生成的版本,你有一个小错误的机会。 如果你认为“嘿,我敢打赌,没有人用过1”,你的可能性比微小。 正是因为我们都认为0和1很酷,所以你有更高的击中几率。
–
当你生成serialVersionUID(3567653491060394677L),而不是使用serialVersionUID(1L)你说的东西。
你说的人可能手动创build或生成其他版本号在这个类的历史上,你不在乎,因为龙是惊人的大数字。
无论哪种方式,除非你完全知道在整个宇宙中已经存在或将要存在的类的序列化时所使用的版本号的历史,否则你就有机会了。 如果你有足够的时间去做100%确定1是AOK,那就去吧。 如果这样做很有效,请继续盲目生成号码。 你更有可能赢得彩票,而不是出错。 如果是这样,让我知道,我会给你买啤酒。
随着玩彩票的所有这些谈话,我可能给你的印象serialVersionUID是随机产生的。 事实上,只要数字的范围均匀分布在一个Long的每个可能的值上,那都可以。 但是,它实际上是这样做的:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
你得到的唯一区别是你不需要一个随机源。 您正在使用类本身中的更改来更改结果。 但根据鸽子的原理,还有可能出现错误和碰撞的机会。 这是不可思议的。 所以祝你好运,让我的啤酒。
然而,即使这个class级只会生活在一个系统和一个代码库中,我们认为用手递增这个数字给你零碰撞的机会就意味着你不了解人类。 🙂
因为在很多情况下,默认的id不是唯一的。 所以我们创造了独特的概念。
那么,serialVersionUID是“静态字段不被序列化”的规则的一个例外。 ObjectOutputStream每次将serialVersionUID的值写入输出stream。 ObjectInputStream将其读回,如果从stream中读取的值与当前版本的类中的serialVersionUID值不一致,则会抛出InvalidClassExceptionexception。 而且,如果在类中没有正式声明的serialVersionUID被序列化,编译器会自动添加一个基于类中声明的字段的值。