La serialización es la conversión del estado de un objeto a un formato que puede almacenarse o transmitirse.
Cuando termina un programa, los objetos que mantenía en memoria dejan de existir. Si queremos conservar sus datos o enviarlos a otro sistema, necesitamos representarlos en otro formato.
Ese proceso se denomina serialización.
¿Qué es serializar?
Es el proceso de convertir un Objeto (que vive en la memoria y tiene una estructura compleja) en una secuencia lineal de bytes (ceros y unos).
- Serializar (Deshidratar): Objeto -> Bytes. (Para guardar en fichero o enviar por red).
- Deserializar (Hidratar): Bytes -> Objeto. (Reconstruir el objeto original).
La serialización nativa (serializable)
Java tiene un mecanismo integrado para esto desde sus inicios. Para que un objeto pueda ser “congelado”, su clase debe implementar la interfaz java.io.Serializable.
Interfaz Marcadora:
Si miras el código de Serializable, verás que está vacía. No tiene métodos. Solo sirve como una “etiqueta” para decirle a la Máquina Virtual de Java: “Oye, está permitido convertir objetos de esta clase en bytes. Me hago responsable.”
Ejemplo práctico
Vamos a guardar un objeto en un archivo .ser y luego recuperarlo.
Paso 1: La Clase
import java.io.Serializable;
public class Videojuego implements Serializable {
// Es buena práctica añadir este ID de versión para evitar errores al deserializar
private static final long serialVersionUID = 1L;
private String titulo;
private int nivel;
// ... constructor, getters y setters ...
}
Paso 2: Escribir (Serializar)
Usamos ObjectOutputStream.
Videojuego partida = new Videojuego("Super Mario", 5);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("partida.ser"))) {
out.writeObject(partida); // Convierte el estado del objeto a bytes
} catch (IOException e) { ... }
Paso 3: Leer (Deserializar)
Usamos ObjectInputStream.
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("partida.ser"))) {
// Recuperamos el objeto (hacemos casting)
Videojuego partidaCargada = (Videojuego) in.readObject();
System.out.println("Nivel recuperado: " + partidaCargada.getNivel());
} catch (IOException | ClassNotFoundException e) { ... }
La palabra clave transient
A veces, hay datos dentro de un objeto que no queremos guardar.
- Una contraseña en texto plano.
- Una conexión a base de datos abierta (no tiene sentido guardarla).
- Un dato temporal calculado.
Para evitar que un campo se guarde, lo marcamos como transient.
public class Usuario implements Serializable {
private String nombre; // Se guarda
private transient String password; // SE IGNORA. Al leer será null.
}
El problema de la serialización nativa
Si es tan fácil, ¿por qué te he dicho que se usa poco hoy en día?
- Es exclusiva de Java: Un archivo
.sergenerado por Java no lo puede leer un programa hecho en Python, JavaScript o C#. Es un formato cerrado. - Es frágil: Si guardas un objeto
Videojuego, y mañana cambias la clase (añades un campo nuevo), al intentar leer el archivo antiguo, Java lanzará unaInvalidClassException. ElserialVersionUIDayuda a controlar esto, pero es doloroso de gestionar. - Seguridad: Deserializar puede ejecutar código de las clases presentes en el proceso. No uses
ObjectInputStreamcon datos que no sean de confianza; si debes mantener este formato, aplica filtros de deserialización y una lista cerrada de tipos permitidos.
La alternativa moderna: JSON
Hoy en día, el mundo está conectado. Java habla con webs (JS), con IAs (Python) y con móviles (Swift). Necesitamos un formato universal.
El estándar actual es serializar a JSON (texto plano). Java SE no incluye un conversor JSON general. Para ello se utilizan librerías externas como Jackson o Gson.
Ejemplo con Jackson
Fíjate qué limpio es. Y el resultado es un archivo de texto .json que cualquiera puede leer.
import com.fasterxml.jackson.databind.ObjectMapper;
// 1. Instanciar el mapper (el traductor)
ObjectMapper mapper = new ObjectMapper();
Videojuego juego = new Videojuego("Zelda", 10);
// 2. Serializar (Java -> JSON)
// Crea un archivo "juego.json" con texto: {"titulo":"Zelda", "nivel":10}
mapper.writeValue(new File("juego.json"), juego);
// 3. Deserializar (JSON -> Java)
Videojuego cargado = mapper.readValue(new File("juego.json"), Videojuego.class);