This is one of the JavaIdioms... You're making a class serializable. So you make it implement the Serializable interface. Now declare:
private static final long serialVersionUID = 1;If you don't define serialVersionUID, the system will make one by hashing most of your class's features. Then if you change anything, the UID will change and Java won't let you reload old data. You can get around this later by figuring out what hash value the system used for the old class and installing it by hand - it will be some random number like:
private static final long serialVersionUID = -403250971215465050L;This isn't a big problem, but it's ugly, prone to typos and it won't compress well. You gain nothing by postponing the declaration. You might as well use a value of 1 from the beginning. Plain and simple.
I feel fairly strongly about this, but that's due to an aesthetic sense that other people may not share. It hurts me to have 8 random bytes in the file when they could be 7 nice clean 0s and a 1. SerialVersionUIDs live forever. It doesn't seem right for them to preserve the accident of the original class feature hash. That data will be irrelevant after the class's first revision.
It took me a while of reading through the Serialization docs to come to this maxim. Then I wished someone had stated it upfront. I'm curious as to what other people do. -- DaveHarris
This idiom matches what we did - we defined a simple uid for all our classes, too. We made it the date - since we were inexperienced and had never used serialization before, we didn't know if we would ever change the uid, but if we did, we wanted to be able to say "all objects stored before this date won't file in":
private static final long serialVersionUID = 19981017L;-- StanSilver
To make the idea (as I'm understanding it) explicit: There is no need to worry about reading in the wrong class of object, just the wrong version of the object's class. Therefore, don't worry about IDs that distinguish classes, just IDs that distinguish incompatible versions of a class. Is that the idea? -- KielHodges
Not quite. It's that the default notion of incompatible versions is typically too strict. If you add a field, it changes the default serialVersionUID which prevents you loading old data, even though that's probably a benign change.
In fact, the stream contains a fullish description of the object's state, including the names and types of all its fields. This information is stored by the system, and it's generally enough for you to convert old data. The system also provides a default conversion (which skips unexpected fields and sets missing fields to their default values), which is often enough - but it's disabled if the serialVersionUID's don't match. -- DaveHarris
One last fun thing about SerialVersionUIDs - they differ by compiler. The UIDs calculated by JikesCompiler differ from those calculated by javac. Apparently, there's no clear specification for how to calculate the UID implicitly, another argument for declaring your own. -- NelsonMinar
(If I recall correctly, the algorithm for computing SerialVersionUIDs looks like it's specified precisely--except that it's actually specified in terms of things (compiler-added initialization methods) that are not specified similarly precisely. -- DanielBarclay?)
As I recall, it's worse than that - different JVM's (or maybe it's class libraries) can result in incompatible serializations as well. The moral the FreeNet project took away from this observation (Kaffe was their compiler in question) was to abandon serialization for hand-written serialization based on the Data{Input,Output}Stream classes. Not only do you get reliable storage independent of the JVM and compiler, but then you don't have to muck around with the version ID's... and you don't have to worry about "transient" declarations.
Maybe it's obvious, but explicitly setting the serialVersionUID one can serialize/deserialize between java and J# quite seamlessly, enabling a little, maybe fragile, communication mean between java and .NET applications. Of course, who can guess the future ... FedericoSpinazzi?
I disagree -- serialVersionUID is there for a reason, and that reason is to avoid mistakenly loading the wrong version of a class during development, causing bizzare bugs that may be hard to track down. In development this usually happens when one sub-project has been recompiled in a distributed system such as a typical J2EE app.
Therefore hardcoding the uid from the start can introduce subtle errors, whereas having the UIDs not match (once you get used to occasionally cryptic errors that indicate this) you just recompile the offending sub-projects.
In *production* it is not only good, but required to have the uid, since different compilers *must* produce different ids, and you don't know what compiler your client bytecode will be built with in some instances.
Different compilers shouldn't produce different UIDs. The Java spec spells out how to generate the UID, what hash to use and what order of members. It's a buggy compiler if it doesn't. That said, javac is one such buggy compiler, which generate UIDs based on __static__ member values.
Related:
Grant Wong 2012