Serialization is a crucial concept in Java that allows you to convert an object into a byte stream, which can then be easily saved to a file or transmitted over a network. This process is particularly important for applications that require the storage or transfer of object state.
Serialization is the process of converting an object into a byte stream, allowing it to be easily saved to disk or sent over a network. The primary goal is to preserve the state of an object, so it can be reconstructed later. Conversely, the process of reconstructing an object from a byte stream is called deserialization.
In Java, serialization is implemented through the Serializable
interface. To make a class serializable, you need to implement this interface.
import java.io.Serializable;
public class MyClass implements Serializable {
private static final long serialVersionUID = 1L; // Recommended
private String name;
private int age;
// Constructor, getters, and setters
}
serialVersionUID
The serialVersionUID
is a unique identifier for each class. It is used during deserialization to ensure that a loaded class corresponds exactly to a serialized object. If no serialVersionUID
is declared, Java will generate one based on various aspects of the class, which can lead to issues if the class definition changes.
import java.io.Serializable;
public class Employee implements Serializable {
private static final long serialVersionUID = 1L; // Unique identifier
private String name;
private int id;
public Employee(String name, int id) {
this.name = name;
this.id = id;
}
@Override
public String toString() {
return "Employee{" + "name='" + name + '\'' + ", id=" + id + '}';
}
}
The serialization process in Java can be done using the ObjectOutputStream
class, which is used to write the object to an output stream.
FileOutputStream
to specify the destination file.ObjectOutputStream
.writeObject()
method to serialize the object.Here’s a complete example demonstrating how to serialize an Employee
object to a file.
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializationExample {
public static void main(String[] args) {
Employee employee = new Employee("John Doe", 12345);
try (FileOutputStream fileOut = new FileOutputStream("employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(employee); // Serialize the object
System.out.println("Serialized data is saved in employee.ser");
} catch (IOException e) {
e.printStackTrace();
}
}
}
Employee
is created.ObjectOutputStream
wraps the FileOutputStream
.employee
object and writes it to the file.Deserialization is the process of reconstructing the object from the byte stream. This is done using the ObjectInputStream
class.
FileInputStream
to specify the source file.ObjectInputStream
.readObject()
method to deserialize the object.Here’s a complete example demonstrating how to deserialize an Employee
object from a file.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserializationExample {
public static void main(String[] args) {
Employee employee = null;
try (FileInputStream fileIn = new FileInputStream("employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
employee = (Employee) in.readObject(); // Deserialize the object
System.out.println("Deserialized Employee: " + employee);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
ObjectInputStream
wraps the FileInputStream
.Employee
object.Employee
.IOException
and ClassNotFoundException
are caught.Sometimes, you may want to exclude certain fields from serialization. This can be achieved using the transient
keyword. Any field marked as transient
will not be serialized.
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private transient String password; // Will not be serialized
public User(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + '}';
}
}
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
public class UserExample {
public static void main(String[] args) {
User user = new User("john_doe", "password123");
// Serialization
try (FileOutputStream fileOut = new FileOutputStream("user.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(user);
System.out.println("Serialized User: " + user);
} catch (IOException e) {
e.printStackTrace();
}
// Deserialization
try (FileInputStream fileIn = new FileInputStream("user.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
User deserializedUser = (User) in.readObject();
System.out.println("Deserialized User: " + deserializedUser);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
password
field is marked as transient
, so it will not be saved during serialization.null
value for the password upon deserialization.In some cases, you may want to control the serialization and deserialization process. This can be done by defining custom methods in your class.
writeObject(java.io.ObjectOutputStream out)
: This method is called during serialization. You can override this method to customize the serialization process.readObject(java.io.ObjectInputStream in)
: This method is called during deserialization. You can override this method to customize the deserialization process.
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
private String street;
private String city;
public Address(String street, String city) {
this.street = street;
this.city = city;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // Write default fields
out.writeUTF("Country: USA"); // Custom field
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // Read default fields
String country = in.readUTF(); // Read custom field
System.out.println("Deserialized Country: " + country);
}
}
InvalidClassException
if serialVersionUID
is not managed properly.