How transient works with final in Serialization Java

I read about the temporary and final keyword, and I found the answer that we cannot use the transient keyword with the final keyword. I tried and got confused because here it works 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 Code class:

 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 a transient keyword.

 ABC04 DEF04 

Exit without a transient keyword.

 ABC34 DEF64 

Can you explain why it is working fine? is there an error

After all, what should be the behavior of the transition process with the final keyword?

+3
java java-8 serialization final transient
Jun 03 '16 at 12:11
source share
2 answers

Your question is somewhat duplicated:

  • final-transient-fields-and-serialization
  • a-transient-final-field-used-as-a-lock-is-null

The final field must be initialized either by directly assigning the initial value, or by the constructor. During deserialization, none of them are called, so the initial values ​​for transients must be set in the private readObject () method, which is called during deserialization. And for this to work, transients must not be final.

and

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

Regarding the results of your test:

Code output with a transient keyword. ABC04 DEF04
Exit without a transient keyword. ABC34 DEF64

transitional

Obviously, the transient field (4th character) is not serialized / deserialized (ABC 3 4-> ABC 0 4 and DEF 6 4-> DEF 0 4)

static

The static field (5 char) also does not deserialize! This is simply because you are executing the operation in the same memory space, and the static field remains in all instances. Therefore, when you set a static field on a student, and then deserialize another student, of course, the static field still has the same meaning!

This also explains why in your test you first set the static field to 2 and then 4 , but only 4 prints. In this case, there is nothing to do with serialization, just a static field.

+6
Jun 03 '16 at 12:48
source share

Your conclusion that your example is working is incorrect.

  • The name field is not transient , so it is stored, restored, and printed correctly.
  • The marks field is declared static ; therefore, it is not part of the state of objects and is never saved or restored. It always shows the last recorded value of 4 , even though your first object wrote 2 on it, because the second object overwrites it with 4 before the test starts.
  • Only the id field is the transient instance field, which is not saved, so the default value of 0 displayed. When the transient keyword is deleted, it is saved and restored, showing 3 for the first and 6 for the second object.

Perhaps this will help you if you add distance or even identifiers, for example, "name="+name+", id="+id+""+", marks="+marks in the string representation returns toString() .

To add another corner case, creating a counter intuitive behavior if you add a field

 transient final int foo = 42; 

for your class, you will also test it to show the correct value after recovery, since it is a compile-time constant. Thus, any code that references this variable will invariably use a constant value and will never read the instance field, so the fact that it has not been restored remains unnoticed. But, of course, such a constant is better declared static, in order to avoid memory loss for the field of the never-read instance.

Another, perhaps surprising example, would be the declaration of transient final fields in enum . They will always be displayed correctly, because the state of enum objects is never saved, but actual, already initialized constant objects of this enum type are resolved by deserializing the enum value.

0
Jun 03 '16 at 13:38 on
source share



All Articles