Search code examples
javaserializationjava-8finaltransient

How transient works with final in Serialization Java


I was reading about transient and final keyword and I found the answer that we can't use transient keyword with final keyword. I tried and got confused because here it working fine.

import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;

public class SerExample{
    public static void main(String... args){
        Student foo = new Student(3,2,"ABC");
        Student koo = new Student(6,4,"DEF");
        try
        {
            FileOutputStream fos = new FileOutputStream("abc.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(foo);
            oos.writeObject(koo);
            oos.close();
            fos.close();
        }
        catch(Exception e){/**/}

        try{
            FileInputStream fis = new FileInputStream("abc.txt");
            ObjectInputStream ois = new ObjectInputStream(fis);
            System.out.println(ois.readObject());
            System.out.println(ois.readObject());
            fis.close();
            ois.close();
        }catch(Exception e){/**/}
    }
}

Here is the Serializable Student class Code:

class Student implements Serializable{
        private transient final int id;
        private transient static int marks;
        private String name;
        public Student(int id, int marks, String name){
            this.id = id;
            this.marks = marks;
            this.name = name;
        }
        public Student(){
            id=0;
        }
        @Override
        public String toString(){
            return (this.name + this.id + this.marks);
        }
    }

Code output with transient keyword.

ABC04
DEF04

Output without transient keyword.

ABC34
DEF64

Can you explain why it's working fine? is there a bug?

At the end what should be behavior of transient with final keyword?


Solution

  • Your question is somewhat a duplicate of this:

    A final field must be initialized either by direct assignment of an initial value or in the constructor. During deserialization, neither of these are invoked, so initial values for transients must be set in the 'readObject()' private method that's invoked during deserialization. And for that to work, the transients must be non-final.

    and

    Any field that is declared transient is not serialized. Moreover, according to this blog post, field values are not even initialized to the values that would be set by a default constructor. This creates a challenge when a transient field is final.

    As for the results of your test:

    Code output with transient keyword. ABC04 DEF04
    Output without transient keyword. ABC34 DEF64

    transient

    Clearly, the transient field (4th character) is not being serialized/deserialized (ABC34->ABC04 and DEF64->DEF04)

    static

    The static field (5th char) is also not being deserialized! It's simply because your are performing the operation in the same memory space, and the static field remains across all instances. So when you set the static field on student, and later deserialize another student, of course the static field still has the same value!

    This also explain why in your test you first set the static field to 2 and then 4, but only 4 gets printed. Nothing to do with serialization in this case, simply static field behavior.