Fazia bastante tempo que eu não lia um capítulo da SCJP 6, mas como eu preciso retomar meus estudos, então, por tabela, tammbém preciso retomar minhas anotações/posts sobre o que eu andar lendo...
Em Ciência da Computação, no contexto de armazenamento e transmissão de dados, a serialização é o processo de salvar um objeto em um meio de armazenamento (como um arquivo de computador ou um buffer de memória) ou transmiti-lo por uma conexão de rede, seja em forma binária ou em formato de texto como o XML. Esta série de bytes pode ser usada para recriar um objeto com o mesmo estado interno que o original. [Wikipedia]
Você, estagiário (não tenho saudades dessa época), vai se lembrar de serialização quando estiver desenvolvendo alguma aplicação web, por exemplo. Eu nunca havia feito serialização manualmente até o momento em que eu li essa seção do livro da SCJP 6.
import java.util.*;
import java.io.*;
class Pessoa implements Serializable {
private String nome;
public Pessoa (String nome){
this.nome = nome;
}
public String getNome() {
return this.nome;
}
public void setNome(String nome){
this.nome = nome;
}
public String toString() {
String result = "nome: " + this.nome;
return result;
}
}
public class Principal {
public static void main(String[] args){
Pessoa pessoa = new Pessoa("Leandro");
String fileName = Pessoa.class.getName() + ".txt";
System.out.println("Antes da serialização - "
+ pessoa);
serializeObject(fileName, pessoa);
Pessoa pessoaNova =
(Pessoa) deserializeObject(fileName);
System.out.println("Depois da serialização - "
+ pessoaNova);
}
public static void serializeObject(
String fileName,
Object object){
try {
FileOutputStream fos =
new FileOutputStream(fileName);
ObjectOutputStream oos =
new ObjectOutputStream(fos);
oos.writeObject(object);
oos.close();
} catch (Exception ex){
ex.printStackTrace();
}
}
public static Object deserializeObject(String fileName){
Object object = null;
try {
FileInputStream fis =
new FileInputStream(fileName);
ObjectInputStream ois =
new ObjectInputStream(fis);
object = ois.readObject();
ois.close();
} catch (Exception ex){
ex.printStackTrace();
}
return object;
}
}
Execute esse código e abra o arquivo Pessoa.txt só por curiosidade. Note que você consegue entender parte do que foi escrito apenas por mera casualidade, pois o Java deve utilizar uma estrutura bem formada para organizar os dados de um objeto num arquivo.
Agora, vamos complicar. E se eu quiser que uma das variáveis de instância da classe Pessoa seja uma referência a outro objeto? Insira no código acima a classe Contato:
class Contato {
private String telefone;
Contato(String telefone){
this.telefone = telefone;
}
public String getTelefone(){
return this.telefone;
}
public void setTelefone(String telefone){
this.telefone = telefone;
}
public String toString() {
String result = "telefone: " + telefone;
return result;
}
}
Modifique a classe Pessoa:
class Pessoa implements Serializable {
private String nome;
private int idade;
private Contato dadosContato;
Pessoa (
String nome,
int idade,
Contato dadosContato){
this.nome = nome;
this.idade = idade;
this.dadosContato = dadosContato
}
...
public int getIdade() {
return this.idade;
}
public void setIdade(int idade){
this.idade = idade;
}
public Contato getDadosContato() {
return this.dadosContato;
}
public void setDadosContato(Contato dadosContato){
this.dadosContato = dadosContato;
}
public String toString() {
String result = "nome: " + this.nome + "\n";
result += "idade: " + this.idade + "\n";
result += "contato - " + this.dadosContato;
return result;
}
}
E a classe Principal também:
public class Principal {
public static void main(String[] args){
Contato dadosContato = new Contato("9876-5432");
Pessoa pessoa =
new Pessoa("Leandro",23, dadosContato);
}
...
}
Agora tente executar novamente. Conseguiu? Eu acho que não...
Como você pode ver, o programa não consegue serializar a propriedade dadosContrato da classe Pessoa, porque a classe Contrato não é serializavel. Você conseguiria resolver esse problema, fazendo a classe Contrato implementar Serializable, mas e se não tiver acesso ao seu código fonte?
Incluindo o modificador de acesso transient à propriedade dadosContrato de Pessoa, você não salva o seu estado quando serializar a instância de Pessoa, acabando com o erro em tempo de execução. Entretanto, vale lembrar que nenhum construtor da classe a ser serializada é chamado, muito menos os valores atribuidos em tempo de declaração das variáveis de instância são usados, o que significa que as variáveis transientes são inicializadas com valores default.
Para testar isso, tente serializar a classe abaixo:
class Teste implements Serializable{
private transient int numero = 42;
private String texto;
Teste() {
this.numero = 25;
this.texto = "Mais um teste";
}
Teste(String texto, int numero){
this.texto = texto;
this.numero = numero;
}
public String getTexto() {
return this.texto;
}
public void setTexto(String texto){
this.texto = texto;
}
public int getNumero() {
return this.numero;
}
public void setNumero(int numero){
this.numero = numero;
}
public String toString(){
String result = "texto: " + this.texto + "\n";
result += "numero: " + this.numero;
return result;
}
}
Mas e se for justamente salvar esta propriedade não serializável o que você precisa?
Você pode, além de fazer esta propriedade virar transient, implementar um par de métodos na sua classe Pessoa, para serializar você mesmo os dados de Contato durante a serialização de Pessoa. Altere a classe Pessoa conforme código abaixo:
class Pessoa implements Serializable {
private String nome;
private int idade;
private transient Contato dadosContato;
...
private void writeObject(ObjectOutputStream os) {
try {
os.defaultWriteObject();
Boolean checkDadosContrato =
(this.dadosContato != null);
os.writeBoolean(checkDadosContrato);
if (checkDadosContrato) {
os.writeObject(this.dadosContato
.getTelefone());
}
} catch (Exception ex){
ex.printStackTrace();
}
}
private void readObject(ObjectInputStream is) {
try {
is.defaultReadObject();
Boolean checkDadosContrato =
is.readBoolean();
if (checkDadosContrato) {
String telefone = (String) is.readObject();
this.dadosContato = new Contato(telefone);
}
} catch (Exception ex){
ex.printStackTrace();
}
}
Acho que agora você consegue executar o programa.
Tá quase acabando, prometo :D Vimos que nenhum construtor da classe serializavel é executado. Vimos que variaveis transientes não são salvas. Vimos como serializar uma propriedade não serializável. Mas e quando a super classe não for serializável? E quanto às variáveis estáticas?
Bem, variáveis estáticas não correspondemm ao estado do objeto (instância da classe) em si. Perceba que todas as instâncias de uma classe compartilham o mesmo valor de uma variável estatica. Que sentido faria salvá-la? E se duas ou mais instâncias de uma classe fossem salvas, qual valor para a variável estática seria utilizado?
Quanto à super classe não serializável... Bem, dissemos que o construtor da classe serializável não é chamado, nem as variáveis de instância são inicializadas com os valores descritos em tempo de declaração. Mas o construtor da primeira classe não serializável é chamado, que chama o construtor da sua super classe, e assim por diante. Quer tirar a dúvida?
class TesteBase {
private long numeroLongo = 100000L;
private String textoBase;
TesteBase() {
textoBase = "texto base";
}
TesteBase(long numeroLongo, String textoBase){
this.numeroLongo = numeroLongo;
this.textoBase = textoBase;
}
public String toString(){
String result =
"textoBase: " + this.textoBase + "\n";
result += "numeroLongo: " + this.numeroLongo;
return result;
}
}
class Teste extends TesteBase implements Serializable{
private transient int numero = 42;
private String texto;
Teste() {
this.numero = 25;
this.texto = "Mais um teste";
}
Teste(
String texto,
int numero,
long numeroLongo,
String textoBase){
super(numeroLongo,textoBase);
this.texto = texto;
this.numero = numero;
}
public String getTexto() {
return this.texto;
}
public void setTexto(String texto){
this.texto = texto;
}
public int getNumero() {
return this.numero;
}
public void setNumero(int numero){
this.numero = numero;
}
public String toString(){
String result =
"texto: " + this.texto + "\n";
result += "numero: " + this.numero + "\n";
result += super.toString();
return result;
}
}





