The Java transient keyword is used on class attributes/variables to indicate that serialization process of such class should ignore such variables while creating a persistent byte stream for any instance of that class.
A transient variable is a variable that can not be serialized. According to Java Language Specification [jls-8.3.1.3] – “Variables may be marked transient to indicate that they are not part of the persistent state of an object.”
In this post, I will discussing various concepts involved around usage of transient keyword in context of serialization.
Table of Contents 1. What is transient keyword in Java? 2. When should we use transient keyword in java? 3. Usage of transient with final keyword 4. Case study: How does a HashMap use transient? 5. Summary Notes1. What is Java transient keyword
The modifier transient in java can be applied to field members of a class to turn off serialization on these field members. Every field marked as transient will not be serialized. You use the transient keyword to indicate to the java virtual machine that the transient variable is not part of the persistent state of an object.
Let’s write an very basic example to understand what exactly above analogy means. I will create an Employee
class and will define 3 attributes i.e. firstName, lastName and confidentialInfo. We do not want to store/save “confidentialInfo” for some purpose so we will mark the field as “transient“.
class Employee implements Serializable { private String firstName; private String lastName; private transient String confidentialInfo; //Setters and Getters }
Now let’s serialize an instance of Employee
class.
try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("empInfo.ser")); Employee emp = new Employee(); emp.setFirstName("Lokesh"); emp.setLastName("Gupta"); emp.setConfidentialInfo("password"); //Serialize the object oos.writeObject(emp); oos.close(); } catch (Exception e) { System.out.println(e); }
Now let’s de-serialize back into java object, and verify if “confidentialInfo” was saved or not?
try { ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("empInfo.ser")); //Read the object back Employee readEmpInfo = (Employee) ooi.readObject(); System.out.println(readEmpInfo.getFirstName()); System.out.println(readEmpInfo.getLastName()); System.out.println(readEmpInfo.getConfidentialInfo()); ooi.close(); } catch (Exception e) { System.out.println(e); }
Program Output.
Lokesh Gupta null
Clearly, “confidentialInfo” was not saved to persistent state while serialization and that’s exactly why we use “transient” keyword in java.
2. When should we use transient keyword in java?Now we have a very knowledge of “transient” keyword. Let’s expand out understanding by identifying the situations where you will need the use of transient keyword.
Loggers
never share the state of an instance. They are just utilities for programming/debugging purpose. Similar example can be reference of a Thread
class. Threads represent a state of a process at any given point of time, and there is no use to store thread state with your instance; simply because they do not constitute the state of your class’s instance.Above four usecases are when you should use the keyword “transient” with reference variables. If you have some more logical cases where “transient” can be used; please share with me and I will update that here in list so that everybody can benefit from your knowledge.
3. Transient with finalRead More : A min guide for implementing serializable interface
I am talking about use of transient with final keyword specifically because it behaves differently in different situations which is not generally the case with other keywords in java.
For making this concept practical, I have modified the Employee class as below:
private String firstName; private String lastName; //final field 1 public final transient String confidentialInfo = "password"; //final field 2 public final transient Logger logger = Logger.getLogger("demo");
Now when I again run the serialization (write/read) again, below is the output:
Program output.
Lokesh Gupta password null
This is strange. We have marked the “confidentialInfo” to transient; and still the field was serialized. For similar declaration, logger was not serialized. Why?
Reason is that whenever any final field/reference is evaluated as “constant expression“, it is serialized by JVM ignoring the presence of transient keyword.
In above example, value “password
” is a constant expression and instance of logger “demo
” is reference. So by rule, confidentialInfo was persisted where as logger was not.
Are you thinking, what if I remove “transient
” from both fields? Well, then fields implementing Serializable
references will persist otherwise not. So, if you remove transient in above code, String (which implements Serializable) will be persisted; where as Logger (which does NOT implements Serializable) will not be persisted AND “java.io.NotSerializableException” will be thrown.
If you want to persist the state of non-serializable fields then use readObject() and writeObject() methods. writeObject()/readObject() are usually chained into serialization/deserialization mechanisms internally and thus called automatically.
4. Case study : How does a HashMap use transient keyword?Read More : SerialVersionUID in java and related fast facts
So far, we have been talking about concepts related to “transient” keyword which are mostly theoretical in nature. Let’s understand the proper use of “transient” which is used inside HashMap
class very logically. It will give you better idea about real life usage of transient keyword in java.
Before understanding the solution which has been created using transient, let’s first identify the problem itself.
HashMap
is used to store key-value pairs, we all know that. And we also know that location of keys inside HashMap
is calculated based on hash code obtained for instance of key. Now when we serialize a HashMap
that means all keys inside HashMap
and all values respective to key’s will also be serialized. After serialization, when we de-serialize the HashMap
instance then all key instances will also be deserialized. We know that during this serialization/deserialization process, there may be loss of information (used to calculate hashcode) as well as most important is it is a NEW INSTANCE itself.
In java, any two instances (even of same class) can not have same hashcode. This is a big problem because the location where keys should be placed according to new hashcodes, are not in there correct positions. When retrieving the value of a key, you will be referring to the wrong index in this new HashMap.
Read More : Working with hashCode and equals methods in java
So, when a hash map is serialized, it means that the hash index, and hence the ordering of the table is no longer valid and should not be preserved. This is the problem statement.
Now look at how it is solved inside HashMap
class. If go through the sourcecode of HashMap.java, you will find below declarations:
transient Entry table[]; transient int size; transient int modCount; transient int hashSeed; private transient Set entrySet;
All important fields have been marked at “transient” (all of them are actually calculated/change at runtime), so they are not part of serialized HashMap
instance. To populate again this important information back, HashMap
class uses writeObject() and readObject() methods as below:
private void writeObject(ObjectOutputStream objectoutputstream) throws IOException { objectoutputstream.defaultWriteObject(); if (table == EMPTY_TABLE) objectoutputstream.writeInt(roundUpToPowerOf2(threshold)); else objectoutputstream.writeInt(table.length); objectoutputstream.writeInt(size); if (size > 0) { Map.Entry entry; for (Iterator iterator = entrySet0().iterator(); iterator.hasNext(); objectoutputstream.writeObject(entry.getValue())) { entry = (Map.Entry) iterator.next(); objectoutputstream.writeObject(entry.getKey()); } } } private void readObject(ObjectInputStream objectinputstream) throws IOException, ClassNotFoundException { objectinputstream.defaultReadObject(); if (loadFactor <= 0.0F || Float.isNaN(loadFactor)) throw new InvalidObjectException((new StringBuilder()) .append("Illegal load factor: ").append(loadFactor).toString()); table = (Entry[]) EMPTY_TABLE; objectinputstream.readInt(); int i = objectinputstream.readInt(); if (i < 0) throw new InvalidObjectException((new StringBuilder()).append("Illegal mappings count: ").append(i).toString()); int j = (int) Math.min((float) i * Math.min(1.0F / loadFactor, 4F), 1.073742E+009F); if (i > 0) inflateTable(j); else threshold = j; init(); for (int k = 0; k < i; k++) { Object obj = objectinputstream.readObject(); Object obj1 = objectinputstream.readObject(); putForCreate(obj, obj1); } }
With above code, HashMap
still let the non-transient fields to be treated as they would normally do, but they wrote the stored key-value pairs at the end of the byte array one after the other. While de-serializing, it let the non-transient variables to be handled by default de-serialization process and then read the key-value pairs one by one. For each key the hash and the index is calculated again and is inserted to the correct position in the table so that it can be retrieved again without any error.
Above use of transient keyword was a very good example of proper usecase. You should keep remember it and mention it whenever it is asked in your next
java interview question.
5. Summary NotesRelated Post: How HashMap works in Java?
That’s all from my side for “transient” keyword. If you want to add something in this post, please do let me know via comments. I will be happy to expand this post.
If you want to learn more concepts like this in future, I will suggest you to join my mailing list/ OR follow me on Google Plus/Facebook or Twitter. I do post interesting links other than howtodoinjava.com in my social profiles.
Happy Learning !!
References:
http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3
http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html
http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#15.28
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4