Java Object Streams: Serialization and File Persistence
Object serialization transforms an in‑memory object into a byte stream; deserialization reconstructs the object from those bytes. Java's ObjectOutputStream and ObjectInputStream work with any underlying stream, allowing objects to be stored in files or transmitted across a network.
Basic writing with ObjectOutputStream
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.ser"))) {
out.writeInt(42);
out.writeDouble(3.14);
out.writeUTF("demo text");
out.writeObject(LocalDate.now());
}
Basic reading with ObjectInputStream
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.ser"))) {
int number = in.readInt();
double value = in.readDouble();
String text = in.readUTF();
LocalDate date = (LocalDate) in.readObject();
// process the values...
}
The Serializable marker interface
Custom classes must implement java.io.Serializable to be eligible for object serialization. This interface contaisn no methods; it simply marks the class as allowed for serialization.
The role of serialVersionUID
Add a static final long serialVersionUID field to your class. It acts as a version identifier. During deserialization the JVM compares the stored UID with the current class UID; a mismatch throws InvalidClassException, preventing data corruption after class changes.
The transient keyword
Fields marked transient are skipped during serialization. On deserialization they receive the default value for their type (0, null, etc.). Static fields are never serialized because they belong to the class, not an individual object.
Example: a Serializable Student class
public class Student implements Serializable {
private static final long serialVersionUID = 20240730L;
private String name;
private transient int enrollmentYear; // will not be persisted
public Student(String name, int enrollmentYear) {
this.name = name;
this.enrollmentYear = enrollmentYear;
}
// getters, setters, toString() omitted for brevity
}
Persisting and recoevring a Student isntance
Student student = new Student("Elena", 2023);
// Write
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("student.ser"))) {
out.writeObject(student);
}
// Read
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.ser"))) {
Student recovered = (Student) in.readObject();
System.out.println(recovered.getName()); // Elena
System.out.println(recovered.getEnrollmentYear()); // 0 (transient default)
}
Ordering constraint
Values must be read in the exact order they were written. If you write an int followed by a String, you must read an int then a String. Any deviation leads to corrupted data or runtime exceptions.