CodeGym /Courses /JAVA 25 SELF /transient fields, serialVersionUID

transient fields, serialVersionUID

JAVA 25 SELF
Level 43 , Lesson 1
Available

1. More about transient

In Java, the transient keyword is a way to tell the serializer: “Please don’t touch this field—forget about it when saving the object!” If you declare a field as transient, it won’t be included in the serialized byte stream. This is especially useful for sensitive data (for example, passwords) or temporary computations that don’t need to be saved.

Example: why do you need transient?

Suppose we have a user class:

import java.io.Serializable;

public class User implements Serializable {
    private String username;
    private transient String password; // We don’t want to save the password!

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    // Getters and setters go here
}

If we serialize an object of this class, the password field won’t go into the file (or any other stream). That means that upon deserialization the password will be equal to its default value — for objects that’s null, for numbers — 0, for booleanfalse.

How does this work in practice?

Let’s run a quick experiment. First, serialize a user:

import java.io.*;

public class TransientDemo {
    public static void main(String[] args) throws Exception {
        User user = new User("vasya", "qwerty123");

        // Save the object to a file
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.ser"));
        out.writeObject(user);
        out.close();

        // Now read the object back
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.ser"));
        User restored = (User) in.readObject();
        in.close();

        System.out.println("Username: " + restored.username);
        System.out.println("Password: " + restored.password);
    }
}

Result:

Username: vasya
Password: null

As you can see, the password field wasn’t restored — it’s transient, so the serializer ignored it.

Where and why to use transient?

  • Passwords and tokens. Never serialize them!
  • Cached or temporary data. For example, if you have a field that can be computed “on the fly.”
  • Objects that can’t or shouldn’t be serialized. For example, references to DB connections, streams, sockets.

Behavior of transient fields

When an object is deserialized, all fields marked transient receive their default values. If you need to restore them, you can use the readObject method and populate them manually (recompute the cache, ask the user for a password, etc.).

2. serialVersionUID: a unique class version identifier

serialVersionUID is a special static field of type long that defines the “version” of a serializable class. During serialization the serialVersionUID value is written; during deserialization the JVM compares it with the value in the current class. If they don’t match, an exception will be thrown and the object won’t be restored.

How to declare serialVersionUID?

Very simple:

private static final long serialVersionUID = 1L;

Typically you declare it right in the class that implements Serializable:

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    // ... other fields and methods
}

Why do we need serialVersionUID?

Imagine you saved an object of a class to a file, and then changed the class structure (added a field, renamed something, etc.). If the serialVersionUID differs, the JVM considers the class incompatible with the old version and won’t let you deserialize the object. This prevents unexpected errors.

What happens if you don’t declare serialVersionUID?

If you don’t declare serialVersionUID explicitly, the compiler will generate it based on the class structure. But even a small change (for example, adding or removing a field) will lead to a different serialVersionUID. As a result, you won’t be able to deserialize objects saved by the old version of the class.

Therefore, it’s recommended to always set serialVersionUID explicitly!

Demonstration: serialVersionUID mismatch

1) First, create a class and serialize an object:

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String username;

    public User(String username) {
        this.username = username;
    }
}

2) Then change serialVersionUID:

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 2L; // Was 1L, now 2L!
    private String username;

    public User(String username) {
        this.username = username;
    }
}

Result:

java.io.InvalidClassException: User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

The JVM clearly warns: “Versions are incompatible!”

What value of serialVersionUID should you choose?

Most often people use simple values (1L, 2L, 42L), and in large projects the IDE can generate “long” values. The main thing is to change it only when the class structure changes in a backward-incompatible way.

3. Practice: transient fields and serialVersionUID in action

Example: a class with a transient field

Let’s modify a sample app (for example, a contacts manager) and add to the user class a field for storing a temporary authorization token that must not be serialized.

import java.io.Serializable;

public class Contact implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private String phone;
    private transient String sessionToken; // temporary token

    public Contact(String name, String phone, String sessionToken) {
        this.name = name;
        this.phone = phone;
        this.sessionToken = sessionToken;
    }

    @Override
    public String toString() {
        return "Contact{" +
               "name='" + name + '\'' +
               ", phone='" + phone + '\'' +
               ", sessionToken='" + sessionToken + '\'' +
               '}';
    }
}

Now let’s try to serialize and deserialize the object:

import java.io.*;

public class TransientAndSUIDDemo {
    public static void main(String[] args) throws Exception {
        Contact c = new Contact("Ivan", "+19990001122", "token-12345");

        // Save the object
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("contact.ser"));
        out.writeObject(c);
        out.close();

        // Restore the object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("contact.ser"));
        Contact restored = (Contact) in.readObject();
        in.close();

        System.out.println("Before serialization: " + c);
        System.out.println("After deserialization: " + restored);
    }
}

Output:

Before serialization: Contact{name='Ivan', phone='+19990001122', sessionToken='token-12345'}
After deserialization: Contact{name='Ivan', phone='+19990001122', sessionToken='null'}

As you can see, the sessionToken field wasn’t restored — it’s transient.

Example: an experiment with serialVersionUID

1) First, serialize an object with serialVersionUID = 1L.
2) Then change serialVersionUID to 2L and try to deserialize the same file.

Result: you’ll get an InvalidClassException, as shown above.

4. Why is it better to set serialVersionUID explicitly?

  • Explicit is better than implicit. You control compatibility: if the class structure hasn’t changed critically, you keep the old serialVersionUID, and objects deserialize without issues.
  • Automatic generation is risky. Any change can alter the computed value and “break” compatibility of saved data.
  • Your IDE will help. Most IDEs (for example, IntelliJ IDEA) can automatically generate serialVersionUID.

5. Common mistakes when working with transient and serialVersionUID

Error #1: forgot to mark a sensitive field as transient.
As a result, passwords or tokens accidentally end up in serialized files. This is not only awkward, but also dangerous.

Error #2: didn’t declare serialVersionUID explicitly.
The class was changed, and now old objects can’t be deserialized: the JVM considers them incompatible, even though the structure might not have changed critically.

Error #3: changed serialVersionUID without necessity.
If you just added a getter or a comment, you don’t need to change serialVersionUID — otherwise old data will stop deserializing.

Error #4: serialVersionUID is not static or not final.
The field must be declared as private static final long serialVersionUID. Otherwise the JVM won’t recognize it correctly.

Error #5: forgot to restore a transient field after deserialization.
If the value is critical to the object’s operation, restore it in readObject — otherwise the object may behave incorrectly.

1
Task
JAVA 25 SELF, level 43, lesson 1
Locked
Timestamp for Personal Data: Entity Versioning
Timestamp for Personal Data: Entity Versioning
1
Task
JAVA 25 SELF, level 43, lesson 1
Locked
Salary Secrets: Temporary Disappearance and Default Restoration
Salary Secrets: Temporary Disappearance and Default Restoration
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION