How to Make a Class Serializable
By Ramakrishna on Jul 21, 2010 in Java Serialization
So far, we’ve focused on the mechanics of serializing an object. We’ve assumed we have a serializable object and discussed, from the point of view of client code, how to serialize it. The next step is discussing how to make a class serializable.
There are four basic things you must do when you are making a class serializable. They are:
1. Implement the Serializable interface.
2. Make sure that instance-level, locally defined state is serialized properly.
3. Make sure that superclass state is serialized properly.
4. Override equals( ) and hashCode( ).
Let’s look at each of these steps in more detail.
Implement the Serializable Interface
This is by far the easiest of the steps. The Serializable interface is an empty interface; it declares no methods at all. So implementing it amounts to adding “implements Serializable” to your class declaration.
Reasonable people may wonder about the utility of an empty interface. Rather than define an empty interface, and require class definitions to implement it, why not just simply make every object serializable? The main reason not to do this is that there are some classes that don’t have an obvious serialization. Consider, for example, an instance of File. An instance of File represents a file. Suppose, for example, it was created using the following line of code:
File file = new File(“c:\\New Floder\\Temp”);
It’s not at all clear what should be written out when this is serialized. The problem is that the file itself has a different lifecyle than the serialized data. The file might be edited, or deleted entirely, while the serialized information remains unchanged. Or the serialized information might be used to restart the application on another machine, where “C:\\New Floder\\Temp” is the name of an entirely different file.
Another example is provided by the Thread[4] class. A thread represents a flow of execution within a particular JVM. You would not only have to store the stack, and all the local variables, but also all the related locks and threads, and restart all the threads properly when the instance is deserialized.
TIP: Things get worse when you consider platform dependencies. In general, any class that involves native code is not really a good candidate for serialization.
Make Sure That Instance-Level, Locally Defined State Is Serialized Properly
Class definitions contain variable declarations. The instance-level, locally defined variables (e.g., the nonstatic variables) are the ones that contain the state of a particular instance. For example, in our Money class, we declared one such field:
public class Money extends ValueObject {
private int _cents;
….
}
The serialization mechanism has a nice default behavior–if all the instance-level, locally defined variables have values that are either serializable objects or primitive datatypes, then the serialization mechanism will work without any further effort on our part. For example, our implementations of Account, such as Account_Impl, would present no problems for the default serialization mechanism:
public class Account_Impl extends UnicastRemoteObject implements Account {
private Money _balance;
…
}
While _balance doesn’t have a primitive type, it does refer to an instance of Money, which is a serializable class.
If, however, some of the fields don’t have primitive types, and don’t refer to serializable classes, more work may be necessary. Consider, for example, the implementation of ArrayList from the java.util package. An ArrayList really has only two pieces of state:
public class ArrayList extends AbstractList implements List, Cloneable, java.io.
Serializable {
private Object elementData[];
private int size;
…
}
But hidden in here is a huge problem: ArrayList is a generic container class whose state is stored as an array of objects. While arrays are first-class objects in Java, they aren’t serializable objects. This means that ArrayList can’t just implement the Serializable interface. It has to provide extra information to help the serialization mechanism handle its nonserializable fields. There are three basic solutions to this problem:
* Fields can be declared to be transient.
* The writeObject( )/readObject( ) methods can be implemented.
* serialPersistentFields can be declared.
