Java serialización y deserialización son conceptos fundamentales en el desarrollo de aplicaciones Java. Este artículo explora qué son, por qué son necesarias y cómo implementarlas en tus proyectos.
- Conceptos de serialización y deserialización en Java
La serialización en Java consiste en convertir objetos Java en secuencias de bytes, mientras que la deserialización es el proceso inverso de reconstruir objetos a partir de esas secuencias de bytes.
- Utilidad de la serialización y deserialización
Cuando dos procesos se comunican de forma remota, pueden intercambiar diversos tipos de datos como texto, imágenes, audio o video, todos transmitidos como secuencias binarias en la red. En el caso de procesos Java, también es posible enviar objetos entre ellos. Para lograr esto, es necesaria la serialización y deserialización de Java. En otras palabras, el emisor debe convertir el objeto Java en una secuencia de bytes para transmitirla por la red, mientras que el receptor necesita reconstruir el objeto Java a partir de esa secuencia.
Entre las ventajas de la serialización en Java destacan:
- Persistencia de datos: Permite guardar datos permanentemente en disco (normalmente en archivos).
- Comunicación remota: Facilita el envío de objetos a través de redes como secuencias de bytes.
-
Implementación de serialización y deserialización en Java
-
APIs de serialización en JDK
java.io.ObjectOutputStream: Representa un flujo de salida de objetos. Su método writeObject(Object obj) serializa el objeto especificado y escribe la secuencia resultante en un flujo de salida de destino.
java.io.ObjectInputStream: Representa un flujo de entrada de objetos. Su método readObject() lee secuencias de bytes del flujo de entrada, las deserializa en un objeto y lo devuelve.
- Requisitos para la serialización
Solo los objetos de clases que implementan la interfaz Serializable o Externalizable pueden ser serializados; de lo contrario, se lanzará una excepción.
- Métodos para implementar serialización y deserialización de objetos Java
Supongamos una clase Alumno cuyos objetos necesitan ser serializados. Existen tres métodos:
Método 1: Si la clase Alumno solo implementa la interfaz Serializable, la serialización y deserialización pueden realizarse de la siguiente manera: ObjectOutputStream utiliza la serialización predeterminada para serializar las variables de instancia no transitorias del objeto Alumno. ObjectInputStream utiliza la deserialización predeterminada para deserializar las variables de instancia no transitorias del objeto Alumno.
Método 2: Si la clase Alumno solo implementa la interfaz Serializable y también define los métodos readObject(ObjectInputStream in) y writeObject(ObjectOutputStream out), entonces se utilizan los siguientes métodos para serialización y deserialización: ObjectOutputStream llama al método writeObject(ObjectOutputStream out) del objeto Alumno para la serialización. ObjectInputStream llama al método readObject(ObjectInputStream in) del objeto Alumno para la deserialización.
Método 3: Si la clase Alumno implementa la interfaz Externalizable y debe implementar los métodos readExternal(ObjectInput in) y writeExternal(ObjectOutput out), entonces la serialización y deserialización se realizan de la siguiente manera: ObjectOutputStream llama al método writeExternal(ObjectOutput out) del objeto Alumno para la serialización. ObjectInputStream llama al método readExternal(ObjectInput in) del objeto Alumno para la deserialización.
- Pasos para la serialización en JDK
Paso 1: Crear un flujo de salida de objetos que pueda envolver otro tipo de flujo de salida de destino, como un flujo de salida de archivo: ObjectOutputStream salida = new ObjectOutputStream(new FileOutputStream("C:\datos\objeto.dat"));
Paso 2: Utilizar el método writeObject() del flujo de salida de objetos para escribir objetos: salida.writeObject("Hola"); salida.writeObject(new Date());
- Pasos para la deserialización en JDK
Paso 1: Crear un flujo de entrada de objetos que pueda envolver otro tipo de flujo de entrada, como un flujo de entrada de archivo: ObjectInputStream entrada = new ObjectInputStream(new FileInputStream("C:\datos\objeto.dat"));
Paso 2: Utilizar el método readObject() del flujo de entrada de objetos para leer objetos: String obj1 = (String)entrada.readObject(); Date obj2 = (Date)entrada.readObject();
Nota: Para leer correctamente los datos y completar la deserialización, el orden en que se escriben los objetos en el flujo de salida debe coincidir con el orden en que se leen desde el flujo de entrada.
A continuación se presenta un ejemplo práctico utilizando el método 1:
Clase Alumno:
import java.io.Serializable;
public class Alumno implements Serializable {
private static final long serialVersionUID = 1L;
private String nombre;
private char genero;
private int edad;
private double promedio;
public Alumno(String nombre, char genero, int edad, double promedio) {
this.nombre = nombre;
this.genero = genero;
this.edad = edad;
this.promedio = promedio;
}
public String getNombre() {
return nombre;
}
public char getGenero() {
return genero;
}
public int getEdad() {
return edad;
}
public double getPromedio() {
return promedio;
}
}
Clase de prueba:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class DemoSerializacion {
public static void main(String[] args) {
try {
Alumno alumno = new Alumno("Maria", 'F', 22, 8.9);
File archivoAlumno = new File("C:/datos/alumno.dat");
// Serialización
OutputStream flujoSalida = new FileOutputStream(archivoAlumno);
ObjectOutputStream flujoObjetos = new ObjectOutputStream(flujoSalida);
flujoObjetos.writeObject(alumno);
flujoObjetos.close();
flujoSalida.close();
// Deserialización
InputStream flujoEntrada = new FileInputStream(archivoAlumno);
ObjectInputStream flujoObjetosEntrada = new ObjectInputStream(flujoEntrada);
Alumno alumnoDeserializado = (Alumno) flujoObjetosEntrada.readObject();
flujoObjetosEntrada.close();
flujoEntrada.close();
// Mostrar datos del objeto deserializado
System.out.println("Nombre: " + alumnoDeserializado.getNombre());
System.out.println("Género: " + alumnoDeserializado.getGenero());
System.out.println("Edad: " + alumnoDeserializado.getEdad());
System.out.println("Promedio: " + alumnoDeserializado.getPromedio());
} catch (Exception e) {
e.printStackTrace();
}
}
}