Java - Serialização

Java fornece um mecanismo, chamado serialização de objeto, onde um objeto pode ser representado como uma sequência de bytes que inclui os dados do objeto, bem como informações sobre o tipo do objeto e os tipos de dados armazenados no objeto.

Depois que um objeto serializado é gravado em um arquivo, ele pode ser lido do arquivo e desserializado, ou seja, as informações de tipo e bytes que representam o objeto e seus dados podem ser usados ​​para recriar o objeto na memória.

O mais impressionante é que todo o processo é independente da JVM, o que significa que um objeto pode ser serializado em uma plataforma e desserializado em uma plataforma totalmente diferente.

Aulas ObjectInputStream e ObjectOutputStream são fluxos de alto nível que contêm os métodos para serializar e desserializar um objeto.

A classe ObjectOutputStream contém muitos métodos de gravação para escrever vários tipos de dados, mas um método em particular se destaca -

public final void writeObject(Object x) throws IOException

O método acima serializa um objeto e o envia para o fluxo de saída. Da mesma forma, a classe ObjectInputStream contém o seguinte método para desserializar um objeto -

public final Object readObject() throws IOException, ClassNotFoundException

Este método recupera o próximo Object fora do stream e o desserializa. O valor de retorno é Object, portanto, você precisará convertê-lo em seu tipo de dados apropriado.

Para demonstrar como a serialização funciona em Java, vou usar a classe Employee que discutimos no início do livro. Suponha que tenhamos a seguinte classe Employee, que implementa a interface Serializable -

Exemplo

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);
   }
}

Observe que para uma classe ser serializada com sucesso, duas condições devem ser atendidas -

  • A classe deve implementar a interface java.io.Serializable.

  • Todos os campos da classe devem ser serializáveis. Se um campo não for serializável, ele deve ser marcadotransient.

Se você está curioso para saber se uma classe padrão Java é serializável ou não, verifique a documentação da classe. O teste é simples: se a classe implementa java.io.Serializable, ela é serializável; caso contrário, não é.

Serializando um objeto

A classe ObjectOutputStream é usada para serializar um Object. O programa SerializeDemo a seguir instancia um objeto Employee e o serializa em um arquivo.

Quando a execução do programa termina, um arquivo chamado employee.ser é criado. O programa não gera nenhuma saída, mas estuda o código e tenta determinar o que o programa está fazendo.

Note - Ao serializar um objeto para um arquivo, a convenção padrão em Java é dar ao arquivo um .ser extensão.

Exemplo

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();
      }
   }
}

Desserializando um objeto

O programa DeserializeDemo a seguir desserializa o objeto Employee criado no programa SerializeDemo. Estude o programa e tente determinar seu resultado -

Exemplo

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);
   }
}

Isso produzirá o seguinte resultado -

Resultado

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

Aqui estão os seguintes pontos importantes a serem observados -

  • O bloco try / catch tenta capturar uma ClassNotFoundException, que é declarada pelo método readObject (). Para que uma JVM seja capaz de desserializar um objeto, ela deve ser capaz de encontrar o bytecode para a classe. Se a JVM não puder encontrar uma classe durante a desserialização de um objeto, ela lançará uma ClassNotFoundException.

  • Observe que o valor de retorno de readObject () é convertido em uma referência de Employee.

  • O valor do campo SSN era 11122333 quando o objeto foi serializado, mas como o campo é temporário, esse valor não foi enviado para o fluxo de saída. O campo SSN do objeto Employee desserializado é 0.