Introdução
Serialização e desserialização são processos importantes em Java que nos permitem converter um objeto em um fluxo de bytes e restaurá-lo de volta em um objeto, respectivamente. Podemos usar serialização e desserialização para salvar ou persistir o estado de objetos, ou para transmitir objetos através de uma rede. Neste laboratório, aprenderemos como serializar e desserializar objetos em Java usando as classes ObjectInputStream e ObjectOutputStream.
Implementar a Interface Serializable
Para tornar nossos objetos serializáveis, precisamos implementar a interface Serializable. Esta é uma interface de marcador (marker interface) que não exige que nenhum método seja implementado. A interface Serializable é usada para indicar à JVM que os objetos desta classe podem ser serializados.
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
// Constructor and getter/setter methods
}
Criar Objetos para Serializar
Crie alguns objetos da classe Student que serializaremos nos próximos passos.
Student student1 = new Student("Alice", 22);
Student student2 = new Student("Bob", 21);
Serializar Objetos
Para serializar um objeto, precisamos criar uma instância de ObjectOutputStream e chamar seu método writeObject(), passando o objeto que queremos serializar. Isso escreverá o objeto como um fluxo de bytes em um arquivo que podemos usar mais tarde para desserialização.
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();
}
}
}
Desserializar Objetos
Para desserializar um objeto, precisamos criar uma instância de ObjectInputStream e chamar seu método readObject() para ler o fluxo de bytes do arquivo que serializamos anteriormente. Isso retornará um Object, que podemos então converter para o tipo de classe 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();
// Print the students
System.out.println(student1);
System.out.println(student2);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Lidar com Campos Transitórios
Se tivermos algum campo em nossa classe que não queremos serializar, podemos declará-los como transient. Campos transient são ignorados durante a serialização e desserialização. Por exemplo, vamos adicionar um campo transient à nossa classe Student que não queremos serializar:
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
private transient String password;
//Constructor, getter/setter methods
}
Personalizar Serialização e Desserialização
Também podemos personalizar o processo de serialização e desserialização implementando os métodos writeObject() e readObject(). Isso pode ser útil se quisermos lidar com campos transient, ou se quisermos realizar processamento adicional durante a serialização e desserialização.
private void writeObject(ObjectOutputStream oos) throws IOException {
// Default serialization
oos.defaultWriteObject();
// Encrypt password before writing to file
String encryptedPassword = encrypt(password);
oos.writeObject(encryptedPassword);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Default deserialization
ois.defaultReadObject();
// Decrypt password after reading from file
String encryptedPassword = (String) ois.readObject();
password = decrypt(encryptedPassword);
}
Gerenciar Versionamento
Se atualizarmos nossa classe adicionando ou removendo propriedades, então a versão da classe muda, o que pode causar erros ao desserializar objetos mais antigos. Podemos lidar com o versionamento usando o campo serialVersionUID para especificar um identificador único para nossa classe. Isso garantirá que a serialização e desserialização funcionem corretamente, mesmo que a definição da classe seja alterada.
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
//Constructor, getter/setter methods
}
Executar o Código
Compile a classe SerializationDemo e execute-a no terminal usando o seguinte comando:
javac SerializationDemo.java
java SerializationDemo
A saída deve mostrar os dados serializados e os objetos desserializados.
Modificar a Classe Estudante
Atualize a classe Student adicionando ou removendo um campo:
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String email; // Adicionado um campo
//Constructor, getter/setter methods
}
Gerenciar Versionamento com SerialVersionUID
Agora que modificamos nossa classe, precisamos lidar com o versionamento atualizando o serialVersionUID. Isso garantirá que ainda possamos desserializar objetos que foram serializados antes da classe ser modificada.
public class Student implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private int age;
private String email; // Adicionado um campo
//Constructor, getter/setter methods
}
Resumo
Neste laboratório, aprendemos como serializar e desserializar objetos em Java usando ObjectInputStream e ObjectOutputStream. Também aprendemos como lidar com campos transient, personalizar o processo de serialização e desserialização e lidar com o versionamento usando serialVersionUID. Serialização e desserialização são processos importantes para salvar e transmitir dados em Java, e podemos usá-los para armazenar o estado atual de nossos objetos e, posteriormente, restaurá-los conforme necessário.



