Serialization in Java

Introduction

Serialization in Java is a mechanism of converting an object's state into a byte stream, so the byte stream can be reverted back into a copy of the object. This is useful for saving an object's state to a file or transmitting it over a network. Java provides built-in support for serialization with the java.io.Serializable interface.

Key Points:

  • Serialization: Converting an object's state into a byte stream.
  • Deserialization: Converting a byte stream back into a copy of the object.
  • Serializable Interface: A marker interface used to indicate that a class can be serialized.
  • transient Keyword: Prevents certain fields from being serialized.

Table of Contents

  1. The Serializable Interface
  2. The Process of Serialization and Deserialization
  3. Customizing Serialization
  4. Using transient Keyword
  5. SerialVersionUID
  6. Example of Serialization and Deserialization
  7. Conclusion

1. The Serializable Interface

To serialize an object, its class must implement the Serializable interface. This is a marker interface, meaning it does not contain any methods.

Example:

import java.io.Serializable;

public class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

2. The Process of Serialization and Deserialization

Serialization

Serialization is the process of writing the state of an object to a byte stream. This is done using ObjectOutputStream.

Example:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializeExample {
    public static void main(String[] args) {
        Person person = new Person("Alice", 30);

        try (FileOutputStream fileOut = new FileOutputStream("person.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            out.writeObject(person);
            System.out.println("Serialized data is saved in person.ser");
        } catch (IOException i) {
            i.printStackTrace();
        }
    }
}

Deserialization

Deserialization is the process of reading a byte stream and converting it back into an object. This is done using ObjectInputStream.

Example:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class DeserializeExample {
    public static void main(String[] args) {
        Person person = null;

        try (FileInputStream fileIn = new FileInputStream("person.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn)) {
            person = (Person) in.readObject();
            System.out.println("Deserialized Person: " + person);
        } catch (IOException | ClassNotFoundException i) {
            i.printStackTrace();
        }
    }
}

3. Customizing Serialization

You can customize the serialization process by defining the following methods in your class:

  • private void writeObject(ObjectOutputStream out) throws IOException
  • private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException

Example:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class CustomPerson implements Serializable {
    private String name;
    private int age;

    public CustomPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        out.writeInt(age + 10);  // Custom logic
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        age = in.readInt() - 10;  // Custom logic
    }

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

4. Using transient Keyword

The transient keyword in Java is used to indicate that a field should not be serialized.

Example:

import java.io.Serializable;

public class TransientPerson implements Serializable {
    private String name;
    private transient int age;  // This field will not be serialized

    public TransientPerson(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

5. SerialVersionUID

The serialVersionUID is a unique identifier for Serializable classes. This ID is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.

Example:

import java.io.Serializable;

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

    private String name;
    private int age;

    public PersonWithUID(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

6. Example of Serialization and Deserialization

Complete Example:

import java.io.*;

public class SerializationDemo {
    public static void main(String[] args) {
        PersonWithUID person = new PersonWithUID("Alice", 30);

        // Serialize the object
        try (FileOutputStream fileOut = new FileOutputStream("personWithUID.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
            out.writeObject(person);
            System.out.println("Serialized data is saved in personWithUID.ser");
        } catch (IOException i) {
            i.printStackTrace();
        }

        // Deserialize the object
        try (FileInputStream fileIn = new FileInputStream("personWithUID.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn)) {
            PersonWithUID deserializedPerson = (PersonWithUID) in.readObject();
            System.out.println("Deserialized Person: " + deserializedPerson);
        } catch (IOException | ClassNotFoundException i) {
            i.printStackTrace();
        }
    }
}

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

    private String name;
    private int age;

    public PersonWithUID(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

Output:

Serialized data is saved in personWithUID.ser
Deserialized Person: PersonWithUID{name='Alice', age=30}

7. Conclusion

Serialization in Java is a powerful feature that allows you to save the state of an object and restore it later. By implementing the Serializable interface, you can easily serialize and deserialize objects. Customizing serialization, using the transient keyword, and understanding serialVersionUID are important aspects of working with serialization effectively.

Summary of Key Points:

  • Serializable Interface: Implement to make a class serializable.
  • Serialization: Use ObjectOutputStream to serialize objects.
  • Deserialization: Use ObjectInputStream to deserialize objects.
  • Customization: Use writeObject and readObject for custom serialization logic.
  • transient Keyword: Prevents certain fields from being serialized.
  • serialVersionUID: Ensures version compatibility during deserialization.

By mastering serialization, you can efficiently save and restore object states in your Java applications.

Comments