Serialización y deserialización en Java

JavaJavaBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

La serialización y la deserialización son procesos importantes en Java que nos permiten convertir un objeto en un flujo de bytes y restaurarlo nuevamente en un objeto respectivamente. Podemos utilizar la serialización y la deserialización para guardar o persistir el estado de los objetos, o para transmitir objetos a través de una red. En este laboratorio, aprenderemos cómo serializar y deserializar objetos en Java utilizando las clases ObjectInputStream y ObjectOutputStream.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("Java")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["Object-Oriented and Advanced Concepts"]) java(("Java")) -.-> java/FileandIOManagementGroup(["File and I/O Management"]) java(("Java")) -.-> java/SystemandDataProcessingGroup(["System and Data Processing"]) java/ObjectOrientedandAdvancedConceptsGroup -.-> java/classes_objects("Classes/Objects") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/class_attributes("Class Attributes") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/constructors("Constructors") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/modifiers("Modifiers") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/serialization("Serialization") java/FileandIOManagementGroup -.-> java/io("IO") java/SystemandDataProcessingGroup -.-> java/object_methods("Object Methods") subgraph Lab Skills java/classes_objects -.-> lab-117950{{"Serialización y deserialización en Java"}} java/class_attributes -.-> lab-117950{{"Serialización y deserialización en Java"}} java/constructors -.-> lab-117950{{"Serialización y deserialización en Java"}} java/modifiers -.-> lab-117950{{"Serialización y deserialización en Java"}} java/serialization -.-> lab-117950{{"Serialización y deserialización en Java"}} java/io -.-> lab-117950{{"Serialización y deserialización en Java"}} java/object_methods -.-> lab-117950{{"Serialización y deserialización en Java"}} end

Implementar la interfaz Serializable

Para que nuestros objetos sean serializables, debemos implementar la interfaz Serializable. Esta es una interfaz marcadora que no requiere que se implementen métodos. La interfaz Serializable se utiliza para indicar al JVM que los objetos de esta clase pueden ser serializados.

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private int age;

    // Constructor y métodos getter/setter
}

Crear objetos para serializar

Crea algunos objetos de la clase Student que serializaremos en los siguientes pasos.

Student student1 = new Student("Alice", 22);
Student student2 = new Student("Bob", 21);

Serializar objetos

Para serializar un objeto, debemos crear una instancia de ObjectOutputStream y llamar a su método writeObject() pasando el objeto que queremos serializar. Esto escribirá el objeto como un flujo de bytes en un archivo que luego podemos utilizar para la deserialización.

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;

public class SerializationDemo {
    public static void main(String[] args) {
        try {
            FileOutputStream fileOut = new FileOutputStream("students.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);

            out.writeObject(student1);
            out.writeObject(student2);

            out.close();
            fileOut.close();

            System.out.println("Serialized data is saved in students.ser file");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Deserializar objetos

Para deserializar un objeto, debemos crear una instancia de ObjectInputStream y llamar a su método readObject() para leer el flujo de bytes del archivo que serializamos anteriormente. Esto devolverá un Object que luego podemos convertir a nuestro tipo de clase original.

import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;

public class SerializationDemo {
    public static void main(String[] args) {
        try {
            FileInputStream fileIn = new FileInputStream("students.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);

            Student student1 = (Student) in.readObject();
            Student student2 = (Student) in.readObject();

            in.close();
            fileIn.close();

            // Imprimir los estudiantes
            System.out.println(student1);
            System.out.println(student2);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Manejar campos transient

Si tenemos campos en nuestra clase que no queremos que se serialicen, podemos declararlos como transient. Los campos transient se ignoran durante la serialización y deserialización. Por ejemplo, agreguemos un campo transient a nuestra clase Student que no queremos que se serialice:

import java.io.Serializable;

public class Student implements Serializable {
    private String name;
    private int age;
    private transient String password;

    //Constructor, métodos getter/setter
}

Personalizar la serialización y deserialización

También podemos personalizar el proceso de serialización y deserialización implementando los métodos writeObject() y readObject(). Esto puede ser útil si queremos manejar campos transient o si queremos realizar un procesamiento adicional durante la serialización y deserialización.

private void writeObject(ObjectOutputStream oos) throws IOException {
    // Serialización predeterminada
    oos.defaultWriteObject();

    // Encriptar la contraseña antes de escribir en el archivo
    String encryptedPassword = encrypt(password);
    oos.writeObject(encryptedPassword);
}

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    // Deserialización predeterminada
    ois.defaultReadObject();

    // Desencriptar la contraseña después de leer del archivo
    String encryptedPassword = (String) ois.readObject();
    password = decrypt(encryptedPassword);
}

Manejar la versionación

Si actualizamos nuestra clase agregando o eliminando propiedades, entonces la versión de la clase cambia, lo que puede causar errores al deserializar objetos antiguos. Podemos manejar la versionación utilizando el campo serialVersionUID para especificar un identificador único para nuestra clase. Esto garantizará que la serialización y la deserialización funcionen correctamente incluso si la definición de la clase cambia.

import java.io.Serializable;

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

    //Constructor, métodos getter/setter
}

Ejecutar el código

Compile la clase SerializationDemo y ejecútela en la terminal utilizando el siguiente comando:

$ javac SerializationDemo.java
$ java SerializationDemo

La salida debe mostrar los datos serializados y los objetos deserializados.

Modificar la clase Student

Actualice la clase Student agregando o eliminando un campo:

public class Student implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private String email; // Se agregó un campo

    //Constructor, métodos getter/setter
}

Manejar la versionación con SerialVersionUID

Ahora que hemos modificado nuestra clase, necesitamos manejar la versionación actualizando el serialVersionUID. Esto garantizará que aún podamos deserializar objetos que se serializaron antes de que se modificara la clase.

public class Student implements Serializable {
    private static final long serialVersionUID = 2L;

    private String name;
    private int age;
    private String email; // Se agregó un campo

    //Constructor, métodos getter/setter
}

Resumen

En este laboratorio, aprendimos cómo serializar y deserializar objetos en Java utilizando ObjectInputStream y ObjectOutputStream. También aprendimos cómo manejar campos transient, personalizar el proceso de serialización y deserialización y manejar la versionación utilizando serialVersionUID. La serialización y la deserialización son procesos importantes para guardar y transmitir datos en Java, y podemos utilizarlas para almacenar el estado actual de nuestros objetos y restaurarlos más tarde según sea necesario.