Java 为什么生成长的 serialVersionUID 而不是简单的 1L?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/888335/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why generate long serialVersionUID instead of a simple 1L?
提问by IAdapter
When class implements Serializable in Eclipse, I have two options: add default serialVersionUID(1L)
or generated serialVersionUID(3567653491060394677L)
. I think that first one is cooler, but many times I saw people using the second option. Is there any reason to generate long serialVersionUID
?
当类在 Eclipse 中实现 Serializable 时,我有两个选择:添加默认serialVersionUID(1L)
或生成的serialVersionUID(3567653491060394677L)
. 我认为第一个更酷,但很多时候我看到人们使用第二个选项。有什么理由产生long serialVersionUID
吗?
采纳答案by Michael Myers
As far as I can tell, that would be only for compatibility with previous releases. This would only be useful if you neglected to use a serialVersionUID before, and then made a change that you know should be compatiblebut which causes serialization to break.
据我所知,这只是为了与以前的版本兼容。这仅在您之前忽略使用 serialVersionUID,然后进行了您知道应该兼容但会导致序列化中断的更改时才有用。
See the Java Serialization Specfor more details.
有关更多详细信息,请参阅Java 序列化规范。
回答by coobird
The purpose of the serialization version UID is to keep track of different versions of a class in order to perform valid serialization of objects.
序列化版本 UID 的目的是跟踪类的不同版本,以便执行对象的有效序列化。
The idea is to generate an ID that is unique to a certain version of an class, which is then changed when there are new details added to the class, such as a new field, which would affect the structure of the serialized object.
这个想法是生成一个 ID 对某个类的某个版本是唯一的,然后当有新的细节添加到类中时会更改 ID,例如新字段,这会影响序列化对象的结构。
Always using the same ID, such as 1L
means that in the future, if the class definition is changed which causes changes to the structure of the serialized object, there will be a good chance that problems arise when trying to deserialize an object.
始终使用相同的 ID,例如1L
意味着将来如果更改类定义导致序列化对象的结构发生变化,那么在尝试反序列化对象时很可能会出现问题。
If the ID is omitted, Java will actually calculate the ID for you based on fields of the object, but I believe it is an expensive process, so providing one manually will improve performance.
如果省略ID,Java实际上会根据对象的字段为您计算ID,但我认为这是一个昂贵的过程,因此手动提供一个会提高性能。
Here's are a couple of links to articles which discuss serialization and versioning of classes:
以下是一些讨论类的序列化和版本控制的文章的链接:
- JDC Tech Tips: February 29, 2000(link broken as of February 2013)
- Discover the secrets of the Java Serialization API
- JDC 技术提示:2000 年 2 月 29 日(截至 2013 年 2 月链接已断开)
- 发现 Java 序列化 API 的秘密
回答by Robin
The main reason for the generated one would be to make it compatible with an existing version of the class that already has persisted copies.
生成一个的主要原因是使其与已经具有持久副本的类的现有版本兼容。
回答by joeforker
If you don't specify a serialVersionUID then Java makes one on the fly. The generated serialVersionUID is that number. If you change something in your class that doesn't really make your class incompatible with previous serialized verisons but changes the hash, then you need to use the generated very-large-number serialVersionUID (or the "expected" number from the error message). Otherwise, if you are keeping track of everything yourself, 0, 1, 2... is better.
如果您不指定 serialVersionUID,则 Java 会即时生成一个。生成的 serialVersionUID 就是那个数字。如果您更改类中的某些内容并不会真正使您的类与以前的序列化版本不兼容,而是更改了哈希,那么您需要使用生成的非常大的 serialVersionUID(或错误消息中的“预期”数字) . 否则,如果您自己跟踪所有内容,则 0、1、2... 更好。
回答by David Schmitt
The "long" default of the serialVersionUID
is the default value as defined by the Java Serialization Specification, calculated from the default serialization behaviour.
的“长”默认serialVersionUID
值是Java 序列化规范定义的默认值,根据默认序列化行为计算。
So if you add the default version number, your class will (de-)serialize faster as long as nothing has structurally changed, but you'll have to take care that if you change the class (add/remove fields) you also update the serial number.
因此,如果您添加默认版本号,只要结构上没有任何变化,您的类就会(反)序列化更快,但是您必须注意,如果您更改类(添加/删除字段),您也会更新序列号。
If you do not have to be compatible to existing bit streams, you can just put 1L
there and increment the version as needed when something changes. That is, when the default serialisation version of the changed class would be different from the default version of the old class.
如果您不必与现有位流兼容,您可以将其放在1L
那里并在发生变化时根据需要增加版本。也就是说,当更改的类的默认序列化版本与旧类的默认版本不同时。
回答by Pankaj Kumar
You absolutely should create a serialVersionUID every time you define
a class that implements java.io.Serializable
. If you don't, one will
be created for you automatically, but this is bad. The auto-generated
serialVersionUID is based on the method signatures of your class, so
if you change your class in the future to add a method (for example),
deserializing the "old" versions of the class will fail. Here's what
can happen:
每次定义实现java.io.Serializable
. 如果您不这样做,系统会自动为您创建一个,但这很糟糕。自动生成的 serialVersionUID 基于您的类的方法签名,因此如果您将来更改您的类以添加方法(例如),反序列化该类的“旧”版本将失败。以下是可能发生的情况:
- Create the first version of your class, without defining the serialVersionUID.
- Serialize an instance of your class to a persistent store; a serialVersionUID is automatically generated for you.
- Modify your class to add a new method, and redeploy your application.
- Attempt to deserialize the instance that was serialized in step 2, but now it fails (when it should succeed), because it has a different auto-generated serialVersionUID.
- 创建类的第一个版本,而不定义 serialVersionUID。
- 将类的实例序列化为持久存储;会自动为您生成一个 serialVersionUID。
- 修改您的类以添加新方法,并重新部署您的应用程序。
- 尝试反序列化在第 2 步中序列化的实例,但现在它失败了(应该成功时),因为它具有不同的自动生成的 serialVersionUID。
回答by Pushpendra Kuntal
Because in many cases default id is not unique. so we create id for making unique concept.
因为在很多情况下默认 id 不是唯一的。所以我们创建 id 来制作独特的概念。
回答by Lucky
Well, serialVersionUID is an exception to the rule that “static fields don't get serialized”. ObjectOutputStream writes every time the value of serialVersionUID to the output stream. ObjectInputStream reads it back and if the value read from the stream does not agree with the serialVersionUID value in the current version of the class, then it throws the InvalidClassException. Moreover, if there is no serialVersionUID officially declared in the class to be serialized, compiler automatically adds it with a value generated based on the fields declared in the class.
好吧,serialVersionUID 是“静态字段不会被序列化”规则的一个例外。ObjectOutputStream 每次将 serialVersionUID 的值写入输出流。ObjectInputStream 读回它,如果从流中读取的值与类的当前版本中的 serialVersionUID 值不一致,则它抛出 InvalidClassException。此外,如果要序列化的类中没有正式声明的serialVersionUID,编译器会自动添加一个根据类中声明的字段生成的值。
回答by SomeGuy
When you use serialVersionUID(1L) rather than generating serialVersionUID(3567653491060394677L) you are saying something.
当您使用 serialVersionUID(1L) 而不是生成 serialVersionUID(3567653491060394677L) 时,您是在说些什么。
You are saying that you are 100% confident that no system that will ever touch this class that has an incompatible serialized version of this class with a version number of 1.
您是说您 100% 确信没有系统会接触此类具有版本号为 1 的不兼容序列化版本的此类。
If you can think of any excuse for it's serialized version history to be unknown, that might be hard to say with confidence. In it's lifetime, a successful class will be maintained by many people, live in many projects, and reside in many systems.
如果你能想到任何借口让它的序列化版本历史未知,那可能很难有信心地说。在它的生命周期中,一个成功的类会被很多人维护,存在于很多项目中,存在于很多系统中。
You can agonize over that. Or you can play the lottery hoping to lose. If you generate the version you have a tiny chance of things going wrong. If you assume "Hey I bet no one used 1 yet" your odds are larger than tiny. It's precisely because we all think 0 and 1 are cool that you have higher odds of hitting them.
你可以为此苦恼。或者你可以玩乐透,希望输。如果您生成该版本,则出现问题的可能性很小。如果您假设“嘿,我敢打赌还没有人用过 1”,那么您的赔率就大了。正是因为我们都认为 0 和 1 很酷,所以你击中它们的几率更高。
-
——
When you generate serialVersionUID(3567653491060394677L) rather than use serialVersionUID(1L) you are saying something.
当您生成 serialVersionUID(3567653491060394677L) 而不是使用 serialVersionUID(1L) 时,您是在说些什么。
You are saying people may have either manually created or generated other version numbers over the history of this class and you don't care because Longs are freaking big numbers.
你是说人们可能在这个类的历史中手动创建或生成了其他版本号,你不在乎,因为 Longs 是大数字。
Either way unless you perfectly know the history of version numbers used when serializing the class in the entire universe of where it has or will ever exist, you're taking a chance. If you have the time to make 100% sure 1 is AOK, go for it. If that's to much work, go ahead and blindly generate the number. You're more likely to win the lottery than to have that go wrong. If it does, let me know and I'll buy you a beer.
无论哪种方式,除非您完全了解在该类已经存在或将存在的整个宇宙中序列化该类时使用的版本号的历史记录,否则您是在冒险。如果您有时间 100% 确定 1 是 AOK,那就去做吧。如果工作量太大,请继续盲目地生成数字。你更有可能赢得彩票而不是出错。如果有,请告诉我,我会请你喝啤酒。
With all this talk of playing the lottery I may have given you the impression that serialVersionUID is generated randomly. In fact as long as the range of numbers is evenly distributed over every possible value of a Long that would be fine. However, it's actually done this way:
说了这么多玩彩票,我可能给你的印象是 serialVersionUID 是随机生成的。事实上,只要数字范围均匀分布在 Long 的每个可能值上就可以了。然而,它实际上是这样做的:
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100
The only difference you get with that is you don't need a source of random. You're using the changes in class itself to change the result. But according to the pigeonhole principle there is still a chance it could go wrong and have a collision. It's just incredibly unlikely. So good luck getting a beer out of me.
你得到的唯一区别是你不需要随机源。您正在使用类本身的更改来更改结果。但是根据鸽巢原理,它仍然有可能出错并发生碰撞。这简直太不可能了。祝你好运从我那里得到啤酒。
However, even if the class will only ever live in one system and one code base, thinking that incrementing the number by hand gives you zero chance of collisions just means you don't understand humans. :)
然而,即使该类只存在于一个系统和一个代码库中,认为手动增加数字会使您发生冲突的机会为零,这意味着您不了解人类。:)
回答by James Drinkard
To add to @David Schmitts answer, as a rule of thumb I would always use the default 1L out of convention. I've only had to go back and change some of them a few times, but I knew that when I made the change and updated the default number by one each time.
要添加到@David Schmitts 的答案中,根据经验,我将始终使用默认的 1L 超出约定。我只需要返回并更改其中一些,但我知道当我进行更改并每次将默认数字更新为 1 时。
At my current company they require the auto-generated number so I use that for convention, but I prefer the default. My take is, if it's not a convention where you work, use the default, unless you think you will be constantly changing the structure of you serialized classes for some reason.
在我目前的公司,他们需要自动生成的数字,所以我使用它来进行约定,但我更喜欢默认值。我的看法是,如果这不是您工作的约定,请使用默认值,除非您认为出于某种原因会不断更改序列化类的结构。