Serialización de objetos en Java: guía completa con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Serialización de objetos en Java: desde lo básico hasta técnicas avanzadas



La serialización es el proceso de convertir el estado de un objeto en un flujo de bytes para guardarlo (en un archivo, base de datos) o transmitirlo por la red. El proceso inverso — la deserialización — restaura el objeto a partir del flujo de bytes. En Java, este mecanismo está integrado en la plataforma y se utiliza ampliamente en sistemas distribuidos, almacenamiento en caché y aplicaciones web. En este artículo, analizaremos cómo funciona la serialización, qué interfaces y clases están involucradas, y cómo implementar correctamente la serialización personalizada.



Fundamentos: la interfaz Serializable



Para que un objeto pueda ser serializado, su clase debe implementar la interfaz marcadora java.io.Serializable. Esta interfaz no contiene métodos — solo le indica a la máquina virtual que el objeto puede ser serializado.



import java.io.Serializable;

public class User implements Serializable { private static final long serialVersionUID = 1L; private String name; private int age;

public User(String name, int age) { this.name = name; this.age = age; }

@Override public String toString() { return "User{name='" + name + "', age=" + age + "}"; }}


El campo serialVersionUID es un identificador único de la versión de la clase. Si no se declara explícitamente, la JVM lo calculará automáticamente, pero esto puede provocar una InvalidClassException durante la deserialización si la clase ha cambiado. Se recomienda definirlo siempre manualmente.



Proceso de serialización y deserialización



Para escribir un objeto en un flujo se utiliza ObjectOutputStream, y para leerlo, ObjectInputStream. Veamos un ejemplo básico:



import java.io.*;

public class SerializationDemo { public static void main(String[] args) { User user = new User("Alexey", 30);

// Serialización try (FileOutputStream fos = new FileOutputStream("user.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeObject(user); System.out.println("Objeto serializado: " + user); } catch (IOException e) { e.printStackTrace(); }

// Deserialización try (FileInputStream fis = new FileInputStream("user.ser"); ObjectInputStream ois = new ObjectInputStream(fis)) { User restoredUser = (User) ois.readObject(); System.out.println("Objeto restaurado: " + restoredUser); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } }}


Durante la deserialización, no se llama al constructor del objeto — el estado se restaura directamente desde el flujo. Esta es una diferencia importante con respecto a la creación normal de objetos mediante new.



La palabra clave transient



A veces es necesario excluir algunos campos de la serialización, por ejemplo, contraseñas o cálculos temporales. Para ello se utiliza el modificador transient. Los campos marcados con él reciben valores predeterminados (0, null, false) durante la serialización.



public class UserWithPassword implements Serializable {    private static final long serialVersionUID = 1L;    private String login;    private transient String password; // no será serializado

public UserWithPassword(String login, String password) { this.login = login; this.password = password; }

@Override public String toString() { return "User{login='" + login + "', password='" + password + "'}"; }}


Después de la deserialización, el campo password será null. Esto es útil para la seguridad, pero requiere lógica adicional para su restauración.



Serialización personalizada: métodos writeObject y readObject



Si el comportamiento estándar no es suficiente, se pueden sobrescribir los métodos privados

Recommendations