The transient keyword marks a field that Java serialization must skip, so the field is not written to the byte stream and gets its default value when the object is read back. It applies only to fields of classes that implement Serializable, and the JVM ignores it everywhere else, although some libraries also honor it.
We mark fields as transient when they hold data that can be recomputed, such as a cache or a derived total, or objects that cannot be serialized, such as a database connection, a thread or a logger. Many JSON libraries also follow the modifier, which makes it a quick way to keep a field out of the output.
The following example serializes a session with a transient cache. The roundTrip() helper and the Session class come from section 1.
Session session = new Session("lokesh");
session.cache.put("theme", "dark");
Session restored = roundTrip(session);
String user = restored.user; // "lokesh"
Map<String, String> cache = restored.cache; // null
Notice that the restored cache is null, not an empty map, because the constructor does not run during deserialization. We look at how the keyword works, how to restore transient fields, the special cases of static and final fields, and how JSON libraries and JPA treat it.
1. How transient Works
Java serialization writes all non-static, non-transient fields of a Serializable object, following references to other objects. A transient field is left out, and when the object is read back, it holds the default value of its type, which is null, 0 or false.

class Session implements Serializable {
final String user;
transient Map<String, String> cache = new HashMap<>();
Session(String user) {
this.user = user;
}
}
@SuppressWarnings("unchecked")
static <T> T roundTrip(T object) throws Exception {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
out.writeObject(object);
}
try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
return (T) in.readObject();
}
}
Deserialization creates the object without running its constructor or its field initializers, so = new HashMap<>() does not run either. Only the constructor of the first non-serializable parent class, often Object, is called.
2. Restoring transient Fields After Deserialization
A transient field often needs a valid value after deserialization. The standard place to set it is a private readObject() method, which the serialization runtime calls instead of its default reading code.
class Cart implements Serializable {
private final List<Integer> prices = new ArrayList<>();
private transient int total; // derived from prices
void add(int price) {
prices.add(price);
total += price;
}
int total() {
return total;
}
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // reads prices
total = prices.stream().mapToInt(Integer::intValue).sum();
}
}
Cart cart = new Cart();
cart.add(30);
cart.add(12);
int restoredTotal = roundTrip(cart).total(); // 42
The @Serial annotation, added in Java 14, lets the compiler check the signature of methods such as readObject(). For a cache, a lazy getter that creates the map on first use is often simpler than readObject().
3. transient with static and final Fields
Static fields are never serialized, because they belong to the class, not to the object, so transient on a static field changes nothing. After deserialization, the field shows whatever value the class has in the current JVM.
A final transient field is a trap. Its initializer does not run during deserialization, so the field stays null or 0 and cannot be fixed in readObject() without reflection. The only exception is a constant, such as a String literal, because the compiler copies its value into every place that reads it.
class Report implements Serializable {
final transient String title = "Sales"; // constant, inlined by javac
final transient List<String> lines = new ArrayList<>(); // not a constant
}
Report copy = roundTrip(new Report());
String title = copy.title; // "Sales"
List<String> lines = copy.lines; // null
Older articles explain the title result by saying that serialization ignores transient for final fields. It does not, and the value is never read from the field at all. In practice, we avoid final transient fields unless they hold constants.
4. Real-World Uses of transient
The JDK itself uses the keyword where serialized data would be wrong or wasteful. In HashMap, the bucket array is transient, and the map writes only its keys and values. The reader rebuilds the buckets, because bucket positions depend on hash codes that can differ in another JVM.
- Caches and computed values, which the reader rebuilds from the serialized data.
- Resources such as connections, streams, threads and locks, which have no meaning in another process.
- Loggers, although a static logger needs no modifier at all.
- Sensitive values such as passwords, with the caveat that leaving a field out of a stream is not real security.
For secrets, transient only keeps the value out of one serialization format. The object still holds it in memory, and logs, heap dumps and other serializers may still expose it, so secrets need proper handling, such as encryption or not storing them at all.
5. transient in JSON Libraries and JPA
Other frameworks reuse the modifier with their own rules.
| Library | Treatment of a transient field |
|---|---|
| Gson | Excluded by default |
| Jackson | Ignored as a field, but still written if it has a public getter, unless MapperFeature.PROPAGATE_TRANSIENT_MARKER is enabled |
| JPA and Hibernate | Not stored in the database, the same as the @Transient annotation |
| Java records | Not allowed, because record fields cannot be transient |
JPA’s @Transient annotation and the transient keyword are not the same thing. The annotation excludes a field from persistence but keeps it in Java serialization, whereas the keyword excludes it from both, which matters when entities are also cached or sent between servers.
6. transient vs volatile
The two modifiers are often confused because both apply to fields and sound technical. They solve unrelated problems.
| transient | volatile | |
|---|---|---|
| Area | Serialization | Multithreading |
| Effect | Field is skipped when the object is serialized | Writes are visible to other threads at once, and reads see the latest write |
| Combined use | Allowed, a field can be both | Allowed |
Java serialization itself is a legacy technology with a long history of security problems, so new designs prefer JSON, Protocol Buffers or records with explicit formats. When we must read serialized data from outside, serialization filters limit which classes can be created.
7. transient Keyword FAQs
Developers who work with serialization ask these questions about transient.
7.1. What value does a transient field have after deserialization?
The default value of its type, null for objects, 0 for numbers and false for boolean, unless readObject() sets it. Field initializers and constructors do not run.
7.2. Can a local variable or a method be transient?
No. The modifier is allowed only on fields, because only fields are part of an object’s serialized state.
7.3. Does transient work with Externalizable?
No. An Externalizable class writes its own state in writeExternal(), so the modifier has no effect there, and the class decides what to write.
7.4. Is transient needed for fields that are not Serializable?
Yes, if the containing class is serialized. A field that refers to a non-serializable object makes writeObject() throw NotSerializableException unless the field is transient or null.
8. Conclusion
The transient keyword keeps a field out of Java serialization, and the field comes back with its default value because constructors and initializers do not run. A readObject() method or a lazy getter restores it.
Static fields are never serialized, and final transient fields stay empty unless they hold constants. Gson and JPA follow the keyword, Jackson follows it only partly, and none of this makes a password secure.
9. References
- JLS 25, transient Fields
- Java Object Serialization Specification, System Architecture
- JEP 415, Context-Specific Deserialization Filters
- Gson User Guide
Happy Learning !!
Sir can you explain why transient key word does’t work with static/final keyword in serialisation ?
“`
public class Bean1 implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9098687921796988767L;
private int field1;
private int field2;
private transient final int field3 = 456*432/123;
public Bean1(int field1, int field2) {
super();
this.field1 = field1;
this.field2 = field2;
}
public int getField1() {
return field1;
}
public void setField1(int field1) {
this.field1 = field1;
}
public int getField2() {
return field2;
}
public void setField2(int field2) {
this.field2 = field2;
}
public int getField3() {
return field3;
}
@Override
public String toString() {
return “Bean1 [field1=” + field1 + “, field2=” + field2 + “]”;
}
}
“`
this is the bean I used to test your 4th point in summary
Whenever any final field/reference is evaluated as “constant expression”, it is serialized by JVM ignoring the presence of transient keyword.
“`
Bean1 o = new Bean1(123, 234);
String filename = “file.ser”;
// Serialization
try
{
//Saving of object in a file
FileOutputStream file = new FileOutputStream(filename);
ObjectOutputStream out = new ObjectOutputStream(file);
// Method for serialization of object
out.writeObject(o);
out.close();
file.close();
System.out.println(“Object has been serialized”);
}
catch(IOException ex)
{
System.out.println(“IOException is caught”);
}
Bean1 object1 = null;
// Deserialization
try
{
// Reading the object from a file
FileInputStream file = new FileInputStream(filename);
ObjectInputStream in = new ObjectInputStream(file);
// Method for deserialization of object
object1 = (Bean1)in.readObject();
in.close();
file.close();
System.out.println(“Object has been deserialized “);
System.out.println(object1.toString());
}
catch(IOException ex)
{
System.out.println(“IOException is caught”);
}
catch(ClassNotFoundException ex)
{
System.out.println(“ClassNotFoundException is caught”);
}
“`
this is the main method code
“`
Object has been serialized
Object has been deserialized
Bean1 [field1=123, field2=234]
“`
this is the output I got and it ignored the transient field even though it is final and has a constant expression.
waiting for your reply
Thank you.
Sorry
Actually it is my mistake
Eclipse didn’t included the transient field
I now included and it is fine.
Thank you, you’d done a great work
HI Lokesh,
Could you explain why it would be a problem during deserialisation as you mentioned there will be loss of information for calculating new hash code.hash code would be calculated based on he method that we override for that specific class right !! Wont the JVM use the same method to calculate the hash code for entires in hash map after deserialisation is done.Do you mean to tell for the scenario where hash code method is not over riden to calculate the hash code and object class code(hash code calculates based on internal memory representation )is applied..please clarify this
Yes, you are right. I am talking about custom implementation of hashCode() method which may include fields which do not take into consideration while serialization. e.g static fields or simply transient fields. If hashCode() is using these fields then after de-serialization they would not be available.
If you have not overridden hashCode() method then hashCode is definitely going to be different, because in JVM no two instances can have same hashcode, right?