Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should an abstract class have a serialVersionUID

In java, if a class implements Serializable but is abstract, should it have a serialVersionUID long declared, or do the subclasses only require that?

In this case it is indeed the intention that all the sub classes deal with serialization as the purpose of the type is to be used in RMI calls.

like image 409
Yishai Avatar asked May 21 '09 14:05

Yishai


People also ask

Does serialVersionUID needed?

Simply put, we use the serialVersionUID attribute to remember versions of a Serializable class to verify that a loaded class and the serialized object are compatible. The serialVersionUID attributes of different classes are independent. Therefore, it is not necessary for different classes to have unique values.

Can abstract class be serialized in Java?

Thanks! Well, no, because you can only serialize objects, and you can't create an instance of an abstract class.

What is a serialVersionUID and why should I use it?

SerialVersionUID is a unique identifier for each class, JVM uses it to compare the versions of the class ensuring that the same class was used during Serialization is loaded during Deserialization. Specifying one gives more control, though JVM does generate one if you don't specify.

What should I set serialVersionUID to?

You should usually have the serialVersionUID as a private static final field in your class; you can choose any value. If you don't specify one, a value is generated automatically (this approach can lead to problems as it is compiler (object structure) dependent.


2 Answers

The serialVersionUID is provided to determine compatibility between a deseralized object and the current version of the class. As such, it isn't really necessary in the first version of a class, or in this case, in an abstract base class. You'll never have an instance of that abstract class to serialize/deserialize, so it doesn't need a serialVersionUID.

(Of course, it does generate a compiler warning, which you want to get rid of, right?)

It turns out james' comment is correct. The serialVersionUID of an abstract base class does get propagated to subclasses. In light of that, you do need the serialVersionUID in your base class.

The code to test:

import java.io.Serializable;  public abstract class Base implements Serializable {      private int x = 0;     private int y = 0;      private static final long serialVersionUID = 1L;      public String toString()     {         return "Base X: " + x + ", Base Y: " + y;     } }    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;  public class Sub extends Base {      private int z = 0;      private static final long serialVersionUID = 1000L;      public String toString()     {         return super.toString() + ", Sub Z: " + z;     }      public static void main(String[] args)     {         Sub s1 = new Sub();         System.out.println( s1.toString() );          // Serialize the object and save it to a file         try {             FileOutputStream fout = new FileOutputStream("object.dat");             ObjectOutputStream oos = new ObjectOutputStream(fout);             oos.writeObject( s1 );             oos.close();         } catch (Exception e) {             e.printStackTrace();         }          Sub s2 = null;         // Load the file and deserialize the object         try {             FileInputStream fin = new FileInputStream("object.dat");             ObjectInputStream ois = new ObjectInputStream(fin);             s2 = (Sub) ois.readObject();             ois.close();         } catch (Exception e) {             e.printStackTrace();         }          System.out.println( s2.toString() );     } } 

Run the main in Sub once to get it to create and save an object. Then change the serialVersionUID in the Base class, comment out the lines in main that save the object (so it doesn't save it again, you just want to load the old one), and run it again. This will result in an exception

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 
like image 179
Bill the Lizard Avatar answered Sep 27 '22 20:09

Bill the Lizard


Yes, in general, for the same reason that any other class needs a serial id - to avoid one being generated for it. Basically any class (not interface) that implements serializable should define serial version id or you risk de-serialization errors when the same .class compile is not in the server and client JVMs.

There are other options if you are trying to do something fancy. I'm not sure what you mean by "it is the intention of the sub classes...". Are you going to write custom serialization methods (eg. writeObject, readObject)? If so there are other options for dealing with a super class.

see: http://java.sun.com/javase/6/docs/api/java/io/Serializable.html

HTH Tom

like image 36
Tom Avatar answered Sep 27 '22 18:09

Tom