In this article, we will discuss Serialization with Inheritance i.e.; IS-A relationship with inheriting class in detail
It’s an easy choice, when both super-class & sub-class are Serializable, because
- When super–class is serializable, properties of super-class will be serialized
- When sub–class is serializable, properties of sub-class as well as inherited properties of super-class will also be serialized
But we need to understand 2 scenarios with respect to IS-A relationship, while serializing & de-serializing sub-class, when
- Super-class implements java.io.Serializable but sub-class doesn’t implement java.io.Serializable
- Sub-class implements java.io.Serializable but super-class doesn’t implement java.io.Serializable
Let’s us discuss serialization with inheritance with 2 demo program
1. Serialization with Inheritance
Case 1: Super-class implements java.io.Serializable but sub-class doesn’t implement java.io.Serializable
- When super-class is serializable, then any class that is extending super-class will also be serializable by default through inheritance principle
- So, here sub-class doesn’t required to implement java.io.Serializable explicitly
- When sub-class is serialized, then sub-class properties as well as inherited super-class properties will also be serialized during serialization process
- Note: To prevent sub class from serializing by default, then we need to override writeObject() and readObject() methods
Step 1.1: Create super-class Customer implementing java.io.Serializable interface
- For any class said to be serializable, then it must implement java.io.Serializable interface
- Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
- Overrides toString() method to print values in desired format
Customer.java
package in.bench.resources.serialization.inheritance;
import java.io.Serializable;
class Customer implements Serializable {
// instance variables
int customerId;
String customerName;
// overriding toString() method
@Override
public String toString() {
return "Customer ["
+ "customerId=" + customerId
+ ", customerName=" + customerName
+ "]";
}
}
Step 1.2: Create sub-class PrivilegedCustomer extending super-class Customer
- For any class said to be serializable, then it must implement java.io.Serializable interface
- But here, sub-class PrivilegedCustomer is also serializable by default, although sub-class doesn’t implement java.io.Serializable interface explicitly
- Because super-class implements serializable interface through inheritance principle
- If any class doesn’t implements serializable interface, then NotSerializableException will be thrown at run time, although program compiles successfully
- Overrides toString() method to print values in desired format
PrivilegedCustomer.java
package in.bench.resources.serialization.inheritance;
class PrivilegedCustomer extends Customer {
// instance variables
float discountRate;
int bonusPoints;
@Override
public String toString() {
return "PrivilegedCustomer ["
+ "customerId=" + customerId
+ ", customerName=" + customerName
+ ", discountRate=" + discountRate
+ ", bonusPoints=" + bonusPoints
+ "]";
}
}
As we are ready with POJOs implementing java.io.Serializable, we will begin with our serialization and de-serialization process from main class
Step 1.3: Serialization and De-Serialization (with Inheritance)
- For any class said to be serializable, then it must implement java.io.Serializable interface directly/indirectly though inheritance
- Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
- To Serialize any Object, we can use ObjectOutputStream & FileOutputStream to write/save to file in binary format
- To De-Serialize any Object, we can use ObjectInputStream & FileInputStream to read/restore from file (which is in binary format) into Java heap memory
- Serializing & De-Serializing sub-class PrivilegedCustomer
SerializationWithInheritance.java
package in.bench.resources.serialization.inheritance;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationWithInheritance {
public static void main(String[] args) {
// creating Privileged Customer object
PrivilegedCustomer serializePrivilegedCustomer =
new PrivilegedCustomer();
// initialize values for privileged customer object
serializePrivilegedCustomer.customerId = 101;
serializePrivilegedCustomer.customerName = "SJ";
serializePrivilegedCustomer.discountRate = 12.5f;
serializePrivilegedCustomer.bonusPoints = 1000;
// time to play with Serialization and De-Serialization process
// creating output stream variables
FileOutputStream fos = null;
ObjectOutputStream oos = null;
// creating input stream variables
FileInputStream fis = null;
ObjectInputStream ois = null;
// creating customer object reference
// to hold values after de-serialization
Customer deSerializePrivilegedCustomer = null;
try {
// for writing or saving binary data
fos = new FileOutputStream("CustomerInheritance.ser");
// converting java-object to binary-format
oos = new ObjectOutputStream(fos);
// writing or saving customer object's value to stream
oos.writeObject(serializePrivilegedCustomer);
oos.flush();
oos.close();
System.out.println("Serialization: Privileged Customer "
+ "object saved to CustomerInheritance.ser file\n");
// reading binary data
fis = new FileInputStream("CustomerInheritance.ser");
// converting binary-data to java-object
ois = new ObjectInputStream(fis);
// reading object's value and casting to Customer class
deSerializePrivilegedCustomer =
(PrivilegedCustomer) ois.readObject();
ois.close();
System.out.println("De-Serialization: "
+ "Privileged Customer object de-serialized "
+ "from CustomerInheritance.ser file\n");
}
catch (FileNotFoundException fnfex) {
fnfex.printStackTrace();
}
catch (IOException ioex) {
ioex.printStackTrace();
}
catch (ClassNotFoundException ccex) {
ccex.printStackTrace();
}
// printing customer object to console using toString() method
System.out.println("Printing privilege customer values "
+ "from de-serialized object... \n"
+ deSerializePrivilegedCustomer);
}
}
Output:
Serialization: Privileged Customer object saved to
CustomerInheritance.ser file
De-Serialization: Privileged Customer object de-serialized
from CustomerInheritance.ser file
Printing privilege customer values from de-serialized object...
PrivilegedCustomer [customerId=101, customerName=SJ,
discountRate=12.5, bonusPoints=1000]
Case 2: Sub-class implements java.io.Serializable but super-class doesn’t implement java.io.Serializable
- Before moving ahead, we should understand whether is it possible to serializable sub-class, if it’s super-class isn’t serializable ?
- The answer is yes, because if the condition to serialize any class on the basis of its super-class implementing java.io.Serializable interface, then no class in Java can be serialized
- Reason: java.lang.Object is the base class for any class defined in Java, and it doesn’t implements java.io.Serializable interface
- In that way, it is very well possible to serialize a sub-class even if its super-class doesn’t implement java.io.Serializable interface
Step 2.1: Create super-class Customer which doesn’t implement java.io.Serializable interafce
- For any class said to be serializable, it must implement java.io.Serializable interface
- Otherwise, NotSerializableException will be thrown at run time, although program compiles successfully
- Overrides toString() method to print values in desired format
Customer.java
package in.bench.resources.serialization.inheritance;
class Customer {
// instance variables
int customerId;
String customerName;
// overriding toString() method
@Override
public String toString() {
return "Customer [customerId=" + customerId
+ ", customerName=" + customerName + "]";
}
}
Step 2.2: Create sub-class PrivilegedCustomer extending super-class Customer and also implementing java.io.Serializable interface
- For any class said to be serializable, then it must implement java.io.Serializable interface
- Here, sub-class PrivilegedCustomer implement java.io.Serializable interface explicitly and also extends super-class Customer
- If any class doesn’t implements serializable interface, then NotSerializableException will be thrown at run time, although program compiles successfully
- Overrides toString() method to print values in desired format
PrivilegedCustomer.java
package in.bench.resources.serialization.inheritance;
import java.io.Serializable;
class PrivilegedCustomer extends Customer implements Serializable {
// instance variables
float discountRate;
int bonusPoints;
@Override
public String toString() {
return "PrivilegedCustomer [customerId=" + customerId
+ ", customerName=" + customerName
+ ", discountRate=" + discountRate
+ ", bonusPoints=" + bonusPoints + "]";
}
}
As we are ready with POJOs implementing java.io.Serializable, we will begin with our serialization and de-serialization process from main class
Step 2.3: Serialization and De-Serialization (with Inheritance)
- The previous case is very simple like any independent class to serialize in Java
- But this case is bit different with respect to serialization and de-serialization process
Serialization process:
- While serializing sub-class, JVM will check if there are any super-class which isn’t implementing java.io.Serializable interface
- Then, inheriting instance variables of non-serializable super-class will be stored to default value ignoring their original values
- Like 0 for Integer, null for String, etc
De-Serialization process:
- While de-serializing sub class, JVM will check if there are any non-serializable super-class
- Then, it will execute instance initialization flow (i.e.; similar to object instantiation flow)
- 1st check: if there are direct initialization at instance variable declaration
- 2nd check: if there are any initialization block for instance variable assignment
- 3rd check: invokes no-argument constructor and looks for instance variable assignment
- To execute 3rd check, non-serializable super-class requires no-argument constructor
- Exception: otherwise InvalidClassException will be thrown
- Note: For any other case, constructor is not invoked with only exception being for non-serializable super-class
- Serializing & De-Serializing sub-class PrivilegedCustomer
SerializationWithInheritance.java
package in.bench.resources.serialization.inheritance;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationWithInheritance {
public static void main(String[] args) {
// creating Privileged Customer object
PrivilegedCustomer serializePrivilegedCustomer =
new PrivilegedCustomer();
// initialize values for privileged customer object
serializePrivilegedCustomer.customerId = 101;
serializePrivilegedCustomer.customerName = "SJ";
serializePrivilegedCustomer.discountRate = 12.5f;
serializePrivilegedCustomer.bonusPoints = 1000;
// time to play with Serialization and De-Serialization process
// creating output stream variables
FileOutputStream fos = null;
ObjectOutputStream oos = null;
// creating input stream variables
FileInputStream fis = null;
ObjectInputStream ois = null;
// creating customer object reference
// to hold values after de-serialization
Customer deSerializePrivilegedCustomer = null;
try {
// for writing or saving binary data
fos = new FileOutputStream("CustomerInheritance.ser");
// converting java-object to binary-format
oos = new ObjectOutputStream(fos);
// writing or saving customer object's value to stream
oos.writeObject(serializePrivilegedCustomer);
oos.flush();
oos.close();
System.out.println("Serialization: Privileged Customer "
+ "object saved to CustomerInheritance.ser file\n");
// reading binary data
fis = new FileInputStream("CustomerInheritance.ser");
// converting binary-data to java-object
ois = new ObjectInputStream(fis);
// reading object's value and casting to Customer class
deSerializePrivilegedCustomer =
(PrivilegedCustomer) ois.readObject();
ois.close();
System.out.println("De-Serialization: "
+ "Privileged Customer object de-serialized "
+ "from CustomerInheritance.ser file\n");
}
catch (FileNotFoundException fnfex) {
fnfex.printStackTrace();
}
catch (IOException ioex) {
ioex.printStackTrace();
}
catch (ClassNotFoundException ccex) {
ccex.printStackTrace();
}
// printing customer object to console using toString() method
System.out.println("Printing privilege customer values "
+ "from de-serialized object... \n"
+ deSerializePrivilegedCustomer);
}
}
Output:
Serialization: Privileged Customer object saved to
CustomerInheritance.ser file
De-Serialization: Privileged Customer object de-serialized
from CustomerInheritance.ser file
Printing privilege customer values from de-serialized object...
PrivilegedCustomer [customerId=0, customerName=null,
discountRate=12.5, bonusPoints=1000]
3. Important points to remember while Serialization with Inheritance:
- If super-class implements java.io.Serializable interface, then all sub-class is also serializable by default
- It is possible to serialize sub-class, even if its corresponding super-class doesn’t implements java.io.Serializable interface
- While serializing sub-class whose super-class doesn’t implements java.io.Serializable interface, then during serialization process inheriting instance variables of non-serializable super-class will be stored to default value ignoring their original values (like 0 for Integer, null for String, etc)
- During de-serialization process, JVM will execute instance initialization flow in 3 steps i.e.;
1. 1st checks direct variable assignment,
2. 2nd check inside initialization block and then
3. finally 3rd check inside no-argument constructor - For 3rd check, it is very must to code no-argument constructor inside non-serializable super-class
- Otherwise, InvalidClassException will be thrown at run time
Related Articles:
- Java – Serialization and De-Serialization Tutorial Index
- Java – Introduction to Serialization and De-Serialization
- Java – Serializable interface
- Java – Transient keyword with Serialization
- Java – Transient keyword with static variable in Serialization
- Java – Transient keyword with final variable in Serialization
- Java – Serializing a variable with transient modifier or keyword
- Java – Order of Serialization and De-Serialization
- Java – Serialization with Aggregation
- Java – Serialization with Inheritance
- Java – Externalization in detail
- Java – Serializable v/s Externalizable
- Java – Importance of SerialVersionUID in Serialization
- Java – Singleton Design pattern with Serialization
- Java – How to construct a singleton class in a multi-threaded environment ?
- Java – Singleton design pattern, restricting Object creation by overriding readResolve() method
- Java – How to stop Serialization ?
- Java – How to serialize and de-serialize ArrayList ?
- Java – Interview question & answers on Serialization and Externalization
References:
- https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
- https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serial-arch.html
- https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html
- https://docs.oracle.com/javase/7/docs/api/java/io/ObjectInputStream.html
- https://docs.oracle.com/javase/7/docs/api/java/io/FileOutputStream.html
- https://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html
- http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3
Happy Coding !!
Happy Learning !!