The central purpose of defining serialVersionUID
is to control serialization compatibility. As other answers and the documentation has noted, unless a specific value is declared, the value is computed from a variety of class characteristics, even ones that don't actually affect the serialized form, such as the signatures of public methods. If you don't provide a serialVersionUID
, and one or more of these characteristics of the class differs between serialization and deserialization, an InvalidClassException
will be thrown.
Now to the question of when one should or should not declare a serialVersionUID
.
If you care about serialization compatibility, you should almost always declare a serialVersionUID
. Doing this is the only possible way to evolve the class and have the serialized form be compatible with other versions of the class. You will probably also have to provide custom readObject
and writeObject
methods and use various mechanisms like readFields
, putFields
, and serialPersistentFields
to control the serialized format, and to cope with potential changes to the serialized format.
By "care about serialization compatibility", suppose you've serialized an object and have stored it in a file or database. Do you expect to have future versions of your system (with evolved versions of the classes) be able to read the stored serialized objects? Or, suppose you serialize objects and send them over a network to other applications that deserialize them. This happens in RMI, or it could happen if you develop your own network protocol that sends and receive serialized objects. If so, then on your network, can you have different versions of your application running in different places on the network, and do you expect them to be able to talk to each other successfully?
If any of the above are true, you care about serialization compatibility, and you need to declare serialVersionUID
.
There are times when you might care about serialization compatibility but when it doesn't make sense to declare a serialVersionUID
. One example is with anonymous inner classes. Such a class can be made serializable, but it's impractical to try to make it compatible, for several reasons. Anonymous inner classes have compiler-generated names that are implementation specific. They can also change across recompiles. AICs also contain references to their enclosing instance and references to any objects that might be captured from the local scope. All of these objects, and their transitive closure, become part of the serial form of an AIC. For these reasons it's a bad idea to serialize AICs, let alone try to achieve serial compatibility for them. In such cases, adding a serialVersionUID
is just a distraction. If you are tempted to serialize AICs, you probably want to restructure the code to serialize something else instead.
There might be times when you don't care about serialization compatibility of different class versions at all.
One example is if you have a closely coupled set of JVMs that are all sharing classes from the same classpath, and they're exchanging serialized objects. Since they are using the same actual classes, there can't be any incompatibility. Declaring a serialVersionUID
for classes in this case is useless busywork. In fact, doing so may conceal errors. In such a multi-JVM scheme, if there is a serialization compatibility error, that indicates some kind of configuration problem, since it means the JVMs are using different classes. You'd want that to be detected as soon as possible, and not declaring serialVersionUID
would cause an error to be manifested more quickly.
Another reason is that Serializable
is inherited, which may cause classes down the inheritance tree to become Serializable
even if they are never intended to be serialized. Again, declaring serialVersionUID
for such classes is useless busywork. There's no formal way for a class to reject its inheritance and "undeclare" serializability. Best practice, though, is for such classes to implement readObject
and writeObject
and for them to unconditionally throw an exception like InvalidObjectException
or NotSerializableException
.
Still another example is that your product requirements (or whatever) might simply decide not to care about serialization compatibility in certain cases or not at all. It's something that you might decide is just "not supported." The JDK itself has taken this approach. In general, most public, serializable classes in the JDK are constrained to be forward and backward serialization compatible. As such, all of these classes declare a serialVersionUID
and take care to deal with missing or added fields. However, some portions of the JDK, most notably AWT and Swing, are explicitly not serialization compatible across releases. Such classes have a disclaimer that warns of serial incompatibility, and instead of declaring a serialVersionUID
, these classes include an annotation @SuppressWarnings("serial")
to eliminate the warnings.
Bottom line is that it's a mistake to slavishly declare serialVersionUID
in every class that happens to inherit Serializable
. There are good reasons to declare it, and there are also good reasons not to declare it. You should decide explicitly.