Está en la página 1de 6

Serializability in Java

It's a mechanism in Java to ensure that the objects of classes implementing java.io.Serializable interface will have the capability of storing their states on a persistent storage that can be loaded back into the memory with the same state whenever needed.

The Serializable interface is only a marker interface and has no methods or fields in it. It just serves the purpose of notifying the JVM about the Class implementing it that the Class may require to save its state on a persistent medium and subsequently may need to restore the same saved state in the memory when needed. The compiler handles it either by identifying serialVersionUID field in the class or by adding one to the class (the next post talks in detail about serialVersionUID) and presence of this field notifies the Runtime Environment to treat the instance creation appropriately.

The subclasses of a Serializable class are automatically Serializable, and if you want to Serialize sub classes of non-serialized classes then you need to ensure that the super class has a no-argument constructor. Reason being, on marking the sub class as a Serialized class, it tries to save and restore the state of public, protected, and package (of course only if accessible) fields of the super class also. The sub class can do this only if the super class has a no-argument constructor. Otherwise, you'll get a runtime exception.

While De-Serialization also the state of the public, protected, and package (only if accessible) fields of the non-serialized super classes are restored using the no-argument constructor of the super class. The state of the fields of the serialized sub-class is restored from the stream.

Custom handling of objects while Serialization/Deserialization

In addition to the default serialization or deserialization of objects, Java also supports special handling of the serialization (or deserialization) of objects. You just need to

implement the following three special methods in that case and do whatever way you want the save/restore of the objects to go. These special methods are:y y y

private void writeObject(java.io.ObjectOutputStream out) throws IOExceptionprivate private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundExceptionprivate private void readObjectNoData() throws ObjectStreamException

writeObject method

As the name suggests, this method is used for writing the state of the object to the output stream passed as its parameter. Usually the defaultWriteObject() method (or methods from the DataOutput interface for primitive types) of the ObjectOutputStream class is used to write non-static and non-transient fields of the current class to the output stream. The defaultWriteObject() method can be called from within a writeObject method only, otherwise it throws NotActiveException. Some I/O error while writing the date to the stream will cause the IOException to be thrown by this method.

readObject method

This method reads the data saved by the writeObject method and restores the state of the object. This method normally calls readDefaultObject() method (or methods from DataInput interface for primitive types) of the ObjectInputStream class to restore the non-static and non-transient fields of the object.

An interesting scenario: Suppose you have a class having 4 non-static and non-transient fields namely fld1, fld2, fld3, and fld4. Now you create an instance and save the state of the object on a persistent medium using writeObject method. Down the line the class evolves and you need to add two new non-static, non-transient fields namely

fld5, fld6. What will happen, if you try to restore the previously saved state of the object with an object reference of the new version of the Class?

Well... nothing serious. Actually the readDefaultObject() method reads the data and the field name from the stream and assigns the corresponding named field of the current object. So, in our case fld1, fld2, fld3, and fld4 will get restored from the stream and the other two fields fld5 and fld6 will continue having default values.

readObjectNoData method

Suppose you have a class named Class1 and you have saved the state of an object of this class on a persistent medium. You send that saved state to some other application, which has a different version of the same class 'Class1'. Say the recipient application is having a version where Class1 extends another class named 'Class2'. Now, if you try to restore the saved state shipped to the recipient application, you need to use readObjectNoData method and not the readObject method. Reason being, the recipient application will try to look for the state of the superclass of Class1, which is Class2 and obviously it won't find that in the saved state. This may happen in that case also where the saved state of the object gets tempered. readObjectNoData method simply initializes the state of the superclass in any of the above two scenarios.

Difference between Externalizable and Serializable in Java One obvious difference that Serializable is a marker interface and doesn't contain any methods whereas Externalizable interface contains two methods: writeExternal(ObjectOutput) and readExternal(ObjectInput). But, the main difference between the two is that Externalizable interface provides complete control to the class implementing the interface over the object serialization process

whereas Serializable interface normally uses default implementation to handle the object serialization process. While implementing Serializable, you are not forced to define any method as it's a marker interface. However, you can use the writeObject or readObject methods to handle the serilaization process of complex objects. But, while implementing Externalizable interface, you are bound to define the two methods: writeExternal and readExternal and all the object serialization process is solely handled by these two methods only. In case of Serializable interface implementation, state of Superclasses are automatically taken care by the default implementation whereas in case of Externalizable interface the implementing class needs to handle everything on its own as there is no default implementation in this case. Example Scenario: when to use what? If everything is automatically taken care by implementing the Serializable interface, why would anyone like to implement the Externalizable interface and bother to define the two methods? Simply to have the complete control on the process. OKay... let's take a sample example to understand this. Suppose we have an object having hundreds of fields (non-transient) and we want only few fields to be stored on the persistent storage and not all. One solution would be to declare all other fields (except those which we want to serialize) as transient and the default Serialization process will automatically take care of that. But, what if those few fields are not fixed at design tiime instead they are conditionally decided at runtime. In such a situation, implementing Externalizable interface will probably be a better solution. Similarly, there may be scenarios where we simply don't want to maintain the state of the Superclasses (which are automatically maintained by the Serializable interface implementation).

Externalizable in Java
It's an interface which subclasses the java.io.Serializable marker interface. This interface contains two methods:
y y

void writeExternal(ObjectOutput out) void readExternal(ObjectInput in)

This interface is implemented by a class to handle the responsibility of saving and

restoring the contents of its instances to (or from) streams by itself, which it does by implementing the above two methods. Only the identity of the class which implements Externalizable interface is saved in the serialization stream. The control is entirely delegated to the class to handle the saving and restoring all of its contents. It needs to take care of the saving/restoring the state of its super types as well.

Every object which requires to be stored is first tested whether it's Externalizable or not. If yes, then the writeExternal() method is called to do the task of saving of contents otherwise the state of the object is saved using ObjectOutputStream (using writeObject() of this class). If the class is not even Serializable (in case the class doesn't even implement java.io.Serialzable interface) then we get NotSerialzableException. Similarly, an Externalizable instance is restored by first using the public no-argument constructor and then by calling the readExternal() method. If the class is not Externalizable, but it's Serializable then the restore is done by ObjectInputStream (readObject() method of this class).

writeExternal method

This method saves the contents of objects either by calling the methods of the DataOutput interface for primitive data types or by calling the writeObject() method of the ObjectOutput interface for all kind of objects (including arrays). This method throws IOException if it encounters any problem while writing the contents to the output stream.

readExternal method

This method restores the contents of objects either by calling the methods of the DataInput interface for primitive data types or by calling the readObject() method of the ObjectInput interface for all kind of objects (including arrays). This method throws either IOException in case it encounters any I/O error while reading from the input stream OR ClassNotFoundException in case the class for the object being restored is not found.

También podría gustarte