Java: serialización

Java proporciona un mecanismo, llamado serialización de objetos, donde un objeto se puede representar como una secuencia de bytes que incluye los datos del objeto, así como información sobre el tipo de objeto y los tipos de datos almacenados en el objeto.

Después de que un objeto serializado se ha escrito en un archivo, se puede leer desde el archivo y deserializar, es decir, la información de tipo y los bytes que representan el objeto y sus datos se pueden usar para recrear el objeto en la memoria.

Lo más impresionante es que todo el proceso es independiente de JVM, lo que significa que un objeto se puede serializar en una plataforma y deserializar en una plataforma completamente diferente.

Clases ObjectInputStream y ObjectOutputStream son flujos de alto nivel que contienen los métodos para serializar y deserializar un objeto.

La clase ObjectOutputStream contiene muchos métodos de escritura para escribir varios tipos de datos, pero destaca un método en particular:

public final void writeObject(Object x) throws IOException

El método anterior serializa un objeto y lo envía al flujo de salida. De manera similar, la clase ObjectInputStream contiene el siguiente método para deserializar un objeto:

public final Object readObject() throws IOException, ClassNotFoundException

Este método recupera el siguiente objeto de la secuencia y lo deserializa. El valor de retorno es Objeto, por lo que deberá convertirlo a su tipo de datos apropiado.

Para demostrar cómo funciona la serialización en Java, usaré la clase Empleado que discutimos al principio del libro. Supongamos que tenemos la siguiente clase de empleado, que implementa la interfaz serializable:

Ejemplo

public class Employee implements java.io.Serializable {
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   
   public void mailCheck() {
      System.out.println("Mailing a check to " + name + " " + address);
   }
}

Tenga en cuenta que para que una clase se serialice correctamente, se deben cumplir dos condiciones:

  • La clase debe implementar la interfaz java.io.Serializable.

  • Todos los campos de la clase deben ser serializables. Si un campo no es serializable, debe marcarsetransient.

Si tiene curiosidad por saber si una clase estándar de Java es serializable o no, consulte la documentación de la clase. La prueba es simple: si la clase implementa java.io.Serializable, entonces es serializable; de lo contrario, no lo es.

Serializar un objeto

La clase ObjectOutputStream se utiliza para serializar un objeto. El siguiente programa SerializeDemo crea una instancia de un objeto Employee y lo serializa en un archivo.

Cuando el programa termina de ejecutarse, se crea un archivo llamado employee.ser. El programa no genera ninguna salida, pero estudia el código e intenta determinar qué está haciendo el programa.

Note - Al serializar un objeto en un archivo, la convención estándar en Java es darle al archivo un .ser extensión.

Ejemplo

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("Serialized data is saved in /tmp/employee.ser");
      } catch (IOException i) {
         i.printStackTrace();
      }
   }
}

Deserializar un objeto

El siguiente programa DeserializeDemo deserializa el objeto Employee creado en el programa SerializeDemo. Estudie el programa y trate de determinar su salida.

Ejemplo

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();
         in.close();
         fileIn.close();
      } catch (IOException i) {
         i.printStackTrace();
         return;
      } catch (ClassNotFoundException c) {
         System.out.println("Employee class not found");
         c.printStackTrace();
         return;
      }
      
      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("Address: " + e.address);
      System.out.println("SSN: " + e.SSN);
      System.out.println("Number: " + e.number);
   }
}

Esto producirá el siguiente resultado:

Salida

Deserialized Employee...
Name: Reyan Ali
Address:Phokka Kuan, Ambehta Peer
SSN: 0
Number:101

Aquí están los siguientes puntos importantes que deben tenerse en cuenta:

  • El bloque try / catch intenta capturar una ClassNotFoundException, que es declarada por el método readObject (). Para que una JVM pueda deserializar un objeto, debe poder encontrar el código de bytes de la clase. Si la JVM no puede encontrar una clase durante la deserialización de un objeto, lanza una ClassNotFoundException.

  • Observe que el valor de retorno de readObject () se convierte en una referencia de empleado.

  • El valor del campo SSN era 11122333 cuando se serializó el objeto, pero debido a que el campo es transitorio, este valor no se envió al flujo de salida. El campo SSN del objeto Employee deserializado es 0.