Serialización de Objetos en Java: Persistencia y Restauración de Objetos
Java proporciona un mecanismo llamado serialización de objetos donde un objeto se representa como una secuencia de bytes que incluye sus datos, información sobre su tipo y los tipos de datos almacenados.
Tras escribir un objeto serializado en un archivo, puede leerse y deserializar: la información de tipo y los bytes recrean el objeto en memoria. El proceso es independiente de la JVM: un objeto serializado en una plataforma puede deserializarse en otra distinta.
Clases Clave
ObjectOutputStream: Flujos de alto nivel para serializar. Método principal:writeObject(Object x).ObjectInputStream: Para deserializar. Método principal:readObject()(retornaObject, requiere cast).
Requisitos para Serializar una Clase
- Implementar la interfaz
java.io.Serializable(interfaz marcador, sin métodos). - Todos los campos deben ser serializables. Si un campo no lo es, márcalo
transient.
Para saber si una clase estándar es serializable: consulta su documentación; si implementa Serializable, lo es.
Ejemplo: Clase Employee Serializable
public class Employee implements java.io.Serializable {
public String name;
public String address;
public transient int SSN; // no se serializa
public int number;
public void mailCheck() {
System.out.println("Enviando cheque a " + name + " " + address);
}
}
Serializando un Objeto
Convención: archivo con extensión .ser.
Ejemplo: SerializeDemo
import java.io.*;
public class SerializeDemo {
public static void main(String[] args) {
Employee e = new Employee();
e.name = "Reyan Ali";
e.address = "Phokka Kuan, Ambehta Peer";
e.SSN = 11122333;
e.number = 101;
try {
FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
out.close();
fileOut.close();
System.out.printf("Datos serializados guardados en /tmp/employee.ser");
} catch (IOException i) {
i.printStackTrace();
}
}
}
Deserializando un Objeto
Ejemplo: DeserializeDemo
import java.io.*;
public class DeserializeDemo {
public static void main(String[] args) {
Employee e = null;
try {
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject(); // cast necesario
in.close();
fileIn.close();
} catch (IOException i) {
i.printStackTrace();
return;
} catch (ClassNotFoundException c) {
System.out.println("Clase Employee no encontrada");
c.printStackTrace();
return;
}
System.out.println("Empleado deserializado...");
System.out.println("Nombre: " + e.name);
System.out.println("Dirección: " + e.address);
System.out.println("SSN: " + e.SSN); // 0 porque es transient
System.out.println("Número: " + e.number);
}
}
Salida:
Empleado deserializado... Nombre: Reyan Ali Dirección: Phokka Kuan, Ambehta Peer SSN: 0 Número: 101
Puntos Importantes
ClassNotFoundException: La JVM debe encontrar el bytecode de la clase al deserializar. Si no, lanza esta excepción.- El retorno de
readObject()esObject; siempre hacer cast al tipo correcto. - Campos
transientno se serializan; al deserializar toman valor por defecto (0paraint,nullpara referencias). staticfields tampoco se serializan (pertenecen a la clase, no a la instancia).
Versionado y serialVersionUID
Para control de versiones entre serialización y deserialización, declara:
private static final long serialVersionUID = 1L;
Si no se declara, la JVM lo calcula automáticamente basado en la estructura de la clase; cambios en la clase pueden invalidar objetos serializados previos.
Casos de Uso Comunes
- Persistencia ligera (guardar estado en archivo).
- Comunicación RMI (Remote Method Invocation).
- Sesiones HTTP en servlets (session replication).
- Caché distribuido.
Alternativas Modernas
Para serialización robusta, multiplataforma y versionable, considera:
- JSON (Jackson, Gson)
- Protocol Buffers (protobuf)
- Avro
La serialización nativa de Java es conveniente pero frágil ante cambios de clase y no es segura para datos no confiables (riesgo de deserialización maliciosa).
Java
- Palabra clave final en Java: Variables, métodos y clases
- Operador instanceof en Java: Guía completa
- Dominando la herencia en Java: Conceptos, tipos y ejemplos prácticos
- Entendiendo las clases anidadas estáticas en Java: Uso, diferencias y ejemplos
- Dominando las clases internas anónimas en Java: Definición, sintaxis y ejemplos prácticos
- Patrón Singleton en Java explicado: Cómo implementarlo y usarlo de forma segura
- Dominando la Reflexión en Java: Inspeccionando clases, métodos y campos en tiempo de ejecución
- Dominando ObjectOutputStream de Java: Serialización, Métodos y Ejemplos Prácticos
- Dominando Java Generics: Construyendo Código Reutilizable y Type-Safe
- Dominando las operaciones de archivos en Java con java.io: creación, lectura, escritura y eliminación
- Domina Java: Entendiendo Objetos, Clases y Conceptos Básicos de POO