As discussed in
Serialization In Java , the process of saving and restoring the object data is called Serialization. The interfaces
Serialization In Java and
Externalizable In Java with Example makes an object serializable. This process is used for storing data to files or for sending data over network.
The below program shows how an object of class which implements
Serializable
can be converted into bytes (serialization) and then it shows how it can be converted back from bytes into object (de-serialization).
Serializable Test
import java.io.*;
class SerializableTest
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
// SERIALIZATION - START
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
Student hemanth = new Student();
hemanth.name = "Hemanth";
hemanth.rollNumber = 25;
hemanth.section = 'C';
System.out.println("Before - " + hemanth.name + " " + hemanth.rollNumber + " " + hemanth.section);
oos.writeObject(hemanth); // LINE A
oos.close();
byte[] objectDataBytes = baos.toByteArray();
// SERIALIZATION - END
// DESERIALIZATION - START
ByteArrayInputStream bais = new ByteArrayInputStream(objectDataBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Student hemanthRestored = (Student) ois.readObject(); // LINE B
System.out.println("After - " + hemanthRestored.name + " " + hemanthRestored.rollNumber + " " + hemanthRestored.section);
ois.close();
// DESERIALIZATION - END
}
}
class Student implements Serializable
{
String name = "";
int rollNumber = 0;
char section = 'A'; // LINE C
}
OUTPUTBefore - Hemanth 25 C
After - Hemanth 25 C
DESCRIPTIONHere we are creating an ObjectOutputStream
using an ByteArrayOutputStream
. Then we are serializing the created hemanth
object into the ObjectOutputStream
at LINE A
. By doing this the object data, basically "Hemanth"
, 25
and C
are converted into bytes and then written into the output stream.
Later the converted bytes data is given as input to ByteArrayInputStream
which in-turn is input to ObjectInputStream
. At LINE B
, using the ObjectInputStream
the object data is read back or de-serialized. Since we know the read object is Student
, we are type casting it to that class.
As you can see the data before serialization and the after serialization is same and both times it prints Hemanth 25 C.
THINGS TO TRY
- Add one more variable
percentage
of type double
to the Student
class and initialize it 75.6
. Change before and after println
statements and see that the value 75.6
is retained even after the de-serialization process.
- Make the
section
variable as transient, by adding the transient
keyword before char
at LINE C
. See that the section will be changed to the default value of 'A'
. As you know, transient
variables will not be serialized.
Although time consuming, the serialization can be done using
Externalizable
interface as well. The below program discusses the same in detail.
Externalizable Test
import java.io.*;
class ExternalizableTest
{
public static void main(String[] args) throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
Student hemanth = new Student("Hemanth", 25, 'C');
System.out.println("Before - " + hemanth.name + " " + hemanth.rollNumber + " " + hemanth.section);
oos.writeObject(hemanth); // LINE A
oos.close();
byte[] objectDataBytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(objectDataBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Student hemanthRestored = (Student) ois.readObject(); // LINE B
System.out.println("After - " + hemanthRestored.name + " " + hemanthRestored.rollNumber + " " + hemanthRestored.section);
ois.close();
}
}
class Student implements Externalizable {
String name = "";
int rollNumber = 0;
char section = 'A';
// CONSTRUCTOR 1
public Student() { }
// CONSTRUCTOR 2
public Student(String name, int rollNumber, char section) {
super();
this.name = name;
this.rollNumber = rollNumber;
this.section = section;
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = in.readUTF();
rollNumber = in.readInt();
// section = in.readChar(); // LINE X
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(rollNumber);
// out.writeChar(section); // LINE Y
}
}
OUTPUTBefore - Hemanth 25 C
After - Hemanth 25 A
DESCRIPTIONHere we are creating an ObjectOutputStream
using an ByteArrayOutputStream
. Then we are serializing the created hemanth
object into the ObjectOutputStream
at LINE A
. By doing this the object data, basically "Hemanth"
, 25
and C
are converted into bytes and then written into the output stream.
Later the converted bytes data is given as input to ByteArrayInputStream
which in-turn is input to ObjectInputStream
. At LINE B
, using the ObjectInputStream
the object data is read back or de-serialized. Since we know the read object is Student
, we are type casting it to that class.
As you can see the data before serialization and the after serialization is note same. This is because in the readExternal
and writeExternal
methods we are not taking care of section
. That is why the value of section
after de-serializing is set to the default value of 'A'
.
This way you can serialize only the member variables you want to serialize and ignore the rest. You can also change how the data is stored.
THINGS TO TRY
- Uncomment
LINE X
and LINE Y
and see that the section
is also retained after the serialization and the value 'C'
is printed.
- Add one more variable
percentage
of type double
to the Student
class and initialize it 75.6
. Change before and after println
statements and see that the value 75.6
is not retained after the de-serialization process. This is because we have not added the code for writing and reading the percentage variable. Change the methods readExternal
and writeExternal
to handle percentage
variable. Please use the methods writeDouble
and readDouble
for the same.
- Remove the default constructor
CONSTRUCTOR 1
and see that the readObject
fails with InvalidClassException
- Remove the type cast to
Student
at LINE B
and see that we get a compilation error since readObject
returns an Object
and not Student
.
- Change the order of the method calls in
readExternal
and writeExternal
and see that if we do not use the same order in both the methods, then we might get inconsistent data or run-time errors.