Lets first take a short look into how serialization works.Here is my simple example
public static void main(String[] args) {
Cat myCat = new Cat("kitty", 10); System.out.println("before:" + myCat.getName() + " " + myCat.getAge());
ObjectOutputStream ous = null; try { FileOutputStream fos = new FileOutputStream("Cat.ser"); ous = new ObjectOutputStream(fos);
ous.writeObject(myCat); ous.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ous != null) {
try {
ous.close();
} catch (IOException e) { }
}
}
ObjectInputStream ois = null; try { FileInputStream fis = new FileInputStream("Cat.ser"); ois = new ObjectInputStream(fis);
myCat = (Cat) ois.readObject();
System.out.println("after:" + myCat.getName() + " " + myCat.getAge());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) { }
}
}
}
The first significant thing has to be remembered is to make Cat class implement Serializable interface (no abstract methods, just a marker interface). Otherwise java.io.NotSerializableException is thrown.
public class Cat implements Serializable{
private int age; private String name;
public Cat(String string, int i) {
name = string; age = i;
} //getters
}
Here the state and the object graph of the myCat object is saved into the file and then it is read from the file and it could be seen that the values of the fields are the same as the values just before saving the object.
But is myCat refers to the same object in the heap?
Actually no, when look before serialization and after deserialization it can seen that the hashcodes values are changed and if the read object is assigned to another cat object and compared myCat object with that cat object the result is false.
Cat newCat = (Cat) ois.readObject(); Sytem.out.println(myCat.equals(newCat));
When reading a new object with the same object graph is created in the heap and its address is assigned to myCat object.
When you serialize an object, Java serialization takes care of saving that object’s entire “object graph.” That means a deep copy of everything the saved object needs to be restored.
Lets change Cat class and extend Cat from Animal which is a non-serializable class.
public class Animal {
String name;
public Animal(String name) {
System.out.println("constructor for Animal");
this.name = name;
}
public Animal() {
System.out.println("Default constructor for Animal");
}
}
And Cat class becomes like this:
public class Cat extends Animal implements Serializable {
private int age;
public Cat(String string, int i) {
super(string); age = i;
} //getters
}
Cat class is serializable but the base class Animal is not. This means only age field could be written and read with the same values. When serialization occurs the no-arg constructor of the Animal class is called so the serialized cat object would have null value for name field.
What would happen if Animal class didn’t have a no-arg constructor? (Remove the code below from Animal class)
public Animal() {
System.out.println("Default constructor for Animal");
}
In this case since the Animal has a constructor with arguments, JVM doesn’t assign a no-arg constructor for this class,java.io. InvalidClassException would occur with the message “com.foo.serialization.Cat; no valid constructor”.