Skip to content

Java Serialization

Java serialization is a mechanism for converting an object's state information into a format (such as a byte sequence) that can be stored or transmitted. Deserialization is the process of reconstructing an object from a byte sequence. This functionality is very useful for persisting object state or transmitting objects over a network.

What is Serialization?

Imagine you create a complex object in your program that contains various state data. When the program closes, this object and its state disappear from memory. If you want to restore this object when the program starts next time, you need to serialize it (write it to a file or database) and deserialize it (read it back from the file or database) when needed.

Serializable Interface

To make an object of a class serializable, the class must implement the java.io.Serializable interface.

  • Serializable is a marker interface that has no methods. It simply indicates to the JVM that objects of this class are allowed to be serialized.
java
import java.io.Serializable;

public class User implements Serializable {
    // Class attributes
    private String name;
    private int age;

    // Constructor, getters, setters, etc...
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{name='" + name + "', age=" + age + "}";
    }
}

Serializing and Deserializing Objects

  • ObjectOutputStream: Used to write objects to an output stream (such as FileOutputStream). Its writeObject() method performs serialization.
  • ObjectInputStream: Used to read objects from an input stream. Its readObject() method performs deserialization.

Example Code

java
import java.io.*;

public class SerializationExample {
    public static void main(String[] args) {
        // 1. Create an object to serialize
        User user = new User("Alice", 30);
        String filename = "user.ser";

        // 2. Serialize object to file
        try (FileOutputStream fileOut = new FileOutputStream(filename);
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            
            out.writeObject(user);
            System.out.println("Object has been serialized to " + filename);

        } catch (IOException e) {
            e.printStackTrace();
        }

        // 3. Deserialize object from file
        User deserializedUser = null;
        try (FileInputStream fileIn = new FileInputStream(filename);
             ObjectInputStream in = new ObjectInputStream(fileIn)) {

            deserializedUser = (User) in.readObject();
            System.out.println("\nObject has been deserialized from " + filename);
            System.out.println("Deserialized object: " + deserializedUser);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

transient Keyword

By default, all non-static fields of an object are serialized. If you don't want a particular field to be serialized (for example, if it's temporary or contains sensitive information like a password), you can mark it with the transient keyword.

java
public class User implements Serializable {
    private String username;
    private transient String password; // This field will not be serialized
    // ...
}

When an object containing a transient field is deserialized, the field's value will be the default value for its type (null for reference types, 0 for numeric types, false for boolean types).

serialVersionUID

The serialization mechanism uses a version number called serialVersionUID to verify that the serialized object and the class loading it are compatible. This is a private static final long type field.

  • Purpose: During deserialization, the JVM compares the serialVersionUID in the file with the serialVersionUID in the class. If they don't match, an InvalidClassException is thrown.
  • Why it's important: If you don't explicitly declare a serialVersionUID, the Java compiler will automatically generate one based on the class structure (fields, methods, etc.). This means if you modify the class (for example, add or remove a field), the automatically generated serialVersionUID will change, making it impossible to deserialize old versions of the object.

Best practice is to always explicitly declare a serialVersionUID in classes that implement the Serializable interface.

java
public class User implements Serializable {
    // Explicitly declare serialVersionUID
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    // ...
}

By explicitly declaring it, even if you make some modifications to the class that don't affect serialization compatibility (such as adding a method), the serialVersionUID remains unchanged, and you can still successfully deserialize old objects.

Content is for learning and research only.