Friday, June 17, 2016

Tutorial on Serialization in Java - Part2

Transient keyword:

When we have a class which implements Serializable interface, that means its eligible for getting serialized but we want few fields not to get serialized then we can place the transient keyword before their declarations to tell the serialization mechanism that the field should not be saved along with the rest of that object's state. Then those transient fields will not be serialized. That means their values will not be saved into bytestream while serialization and when deserialization, those transient fields will be stored back into the object with their default values.

For example, 

If we put transient keyword in the fields’ declarations of the TestObject class like below:

TestObject.java

package Serialization;

import java.io.Serializable;

public class TestObject implements Serializable {
       transient int number;
       transient String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

If you compile and run ‘SerializationTest.java’, you will get the following output:

Number: 0
Name: null

Here, the field  ‘number’ is a date type of integer and hence its value is stored as int default value ‘0’ and the field  ‘name’ is a date type of String and hence its value is stored as String default value ‘null’.

Can we serialize static fields?

No, we can’t serialize static fields as static fields belong to class not to any object. There is only a single copy of static field values and all objects share these values. If any object modifies the static field value then that modified values will be seen by all other remaining objects of that class which contains the static field.

For example, If we put static keyword in the name field declarations of the TestObject class like below:

TestObject.java

package Serialization;

import java.io.Serializable;

public class TestObject implements Serializable {
       int number;
       static String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

If you compile and run SerializationTest.java, you will get the following output:

Number: 10
Name: TestSerialization

Ooh… still gets the value for our static field name after deserialization and seems contradictory to my statement??

NO. Don’t get confuse here. Actually here the value of name field is taken from class (TestObject) not from deserialized object (tObj2).  The static field name of TestObject gets value “TestSerialization” when the creation of tObj1 object in main() method of SerializationTest class
TestObject  tObj1 = new TestObject(10, "TestSerialization");

Like we are told, only one copy of static fields will be there and shared by all other objects. So while creation of tObj1 object, the static field name has been initialized with the value “TestSerialization” and that is persisted and visible to all other objects. So it’s also visible to the object tObj2 and hence the value of name is getting printed as “TestSerialization”.

So If you create an object tObj3 just before printing the deserialized object values in the main method of SerializationTest as like below:

SerializationTest.java

package Serialization;

public class SerializationTest {
       public static void main(String[] args) {
              TestObject tObj1 = new TestObject(10, "TestSerialization");
              SerializeUtility utility = new SerializeUtility();
             
              // serialization
              utility.serialize(tObj1);
              // deserialization
              TestObject tObj2 = (TestObject)utility.deSerialize();
             
              TestObject tObj3 = new TestObject(100, "NoStatic");
             
              System.out.println("Number: " + tObj2.number);
              System.out.println("Name: " + tObj2.name);
       }
}

If you compile and run SerializationTest.java, you will get the following output:

Number: 10
Name: NoStatic

The static field ‘name’ is assigned with the value “NoStatic” when we created an object tObj3. number field is being deserialized and stored back its value 10 but whereas name field value is taken from the class as it’s not being serialized as it’s a static field.


What happens If a variable is defined as static and transient both?

If a variable is defined as static and transient both then static modifier will govern the behavior of variable and not transient. Transient will be ignored if it’s accompanied with the static.


What happens If a variable is defined as final and transient both?

Suppose if we have number field of TestObject class with both final and transient modifiers as shown below:

TestObject.java

package Serialization;

import java.io.Serializable;

public class TestObject implements Serializable {
       final transient int number;
       String name;
       TestObject(int i, String s) {
              number = i;
              name = s;
       }
}

If you compile and run SerializationTest.java, you will get the following output:

Number: 0
Name: TestSerialization

Since number variable is transient, it is not serialized and therefore, when the object is deserialized, it is initialized to its default value 0. Since the variable number is final, when we try to manually set the value to the variable number then we get the compile time exception by saying “The final field TestObject.number cannot be assigned”.

To get rid of this situation, we need to initialize the final variable number with a constant expression. A constant expression is an expression, which can be resolved at compile time, just like the ones we use in the case labels of switch statement. Then the final field number gets its value 100 during deserialization though its transient.

When we have the variable number initialized in the class TestObject as shown below:

TestObject.java

package Serialization;

import java.io.Serializable;

public class TestObject implements Serializable {
       final transient int number = 100;
       String name;
       TestObject(int i, String s) {
//            number = i;
              name = s;
       }
}

If you compile and run SerializationTest.java, you will get the following output:

Number: 100
Name: TestSerialization

No comments:

Post a Comment