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.
Serializableis a marker interface that has no methods. It simply indicates to the JVM that objects of this class are allowed to be serialized.
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 asFileOutputStream). ItswriteObject()method performs serialization.ObjectInputStream: Used to read objects from an input stream. ItsreadObject()method performs deserialization.
Example Code
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.
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
serialVersionUIDin the file with theserialVersionUIDin the class. If they don't match, anInvalidClassExceptionis 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 generatedserialVersionUIDwill 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.
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.