Neste artigo, explicaremos o que é serialização e como funciona em Java.
Figura 1. Representação gráfica de Threads
Os fluxos são divididos principalmente em dois tipos:
Introdução
A serialização de objetos é a capacidade de um objeto armazenar uma cópia completa de si mesmo e de quaisquer outros objetos aos quais ele faz referência usando um fluxo de saída (por exemplo, para um arquivo externo). Dessa forma, o objeto pode ser recriado a partir da cópia serializada (salva) um pouco mais tarde, quando necessário. A serialização de objetos, um novo recurso introduzido no JDK 1.1, fornece uma função para converter grupos ou objetos individuais, em um fluxo de bits ou matriz de bytes, para armazenamento ou transmissão em uma rede. E como afirmado, um determinado fluxo de bits ou matriz de bytes pode ser convertido novamente em objetos Java. Isso acontece principalmente automaticamente graças às classesObjectInputStream
e ObjectOutputStream
. O programador pode decidir implementar esta funcionalidade implementando a interface Serializable
ao criar a classe. O processo de serialização também é conhecido como empacotamento de objetos , enquanto a desserialização é conhecida como desempacotamento . A serialização é um mecanismo que permite que um objeto salve uma cópia de si mesmo e de todos os outros objetos referenciados por esse objeto em um arquivo externo usando a extensão ObjectOutputStream
. Os objetos salvos podem ser estruturas de dados, diagramas, objetos de classe JFrame
ou quaisquer outros objetos, independentemente do seu tipo. Ao mesmo tempo, a serialização armazena informações sobre o tipo de objeto para que mais tarde, quando desserializado, essas informações sejam usadas para recriar o tipo exato de objeto que era. Portanto, a serialização fornece os seguintes recursos:
- Um sistema para armazenar objetos, ou seja: salvar suas propriedades em um arquivo externo, em disco ou em um banco de dados.
- Sistema de chamada de procedimento remoto.
- Um sistema de distribuição de objetos, por exemplo, em componentes de software como COM, COBRA.
- Sistema para identificar alterações em dados variáveis ao longo do tempo.
Fluxos:
Todo programa deve gravar seus dados em um local de armazenamento ou canal, e todo programa deve ler dados de um canal ou local de armazenamento. Em Java, esses canais onde os programas gravam e dos quais os programas leem dados são chamados de Streams(Stream
) .
- Classes de fluxo de bytes chamadas *Streams
- Classes de fluxo de caracteres chamadas *Reader e *Writer
Persistência
A persistência do objeto é a capacidade de um objeto sobreviver ou, em outras palavras, “sobreviver” à execução de um programa. Isso significa que qualquer objeto criado em tempo de execução será destruído pelo limpador JVM sempre que esse objeto não for mais usado. Mas se a API de persistência for implementada, esses objetos não serão destruídos pelo scavenger JVM, em vez disso poderão “viver”, o que também possibilita acessá-los na próxima vez que a aplicação for iniciada. Em outras palavras, persistência significa que existe um tempo de vida para um objeto, independente do tempo de vida da aplicação que está sendo executada. Uma maneira de implementar a persistência é armazenar objetos em algum lugar de um arquivo ou banco de dados externo e, em seguida, restaurá-los posteriormente usando esses arquivos ou o banco de dados como fontes. É aqui que a serialização entra em jogo. Qualquer objeto não persistente existe enquanto a JVM estiver em execução. Objetos serializados são simplesmente objetos convertidos em fluxos, que são então salvos em um arquivo externo ou transferidos por uma rede para armazenamento e recuperação.Implementação da interface serializável
Qualquer classe deve implementar uma interfacejava.io.Serializable
para serializar objetos dessa classe. A interface Serializable
não possui métodos e apenas marca a classe para que ela possa ser identificada como serializável. Somente os campos de um objeto de classe serializado podem ser salvos. Métodos ou construtores não são armazenados como parte do fluxo serializado. Se algum objeto atuar como referência para outro objeto, os campos desse objeto também serão serializados se a classe desse objeto implementar a interface Serializable
. Em outras palavras, o gráfico deste objeto assim obtido é totalmente serializável. Um gráfico de objeto inclui uma árvore ou estrutura de campos de um objeto e seus subobjetos. Duas classes principais que ajudam a implementar a interface Seriliazable
:
ObjectInputStream
ObjectOutputStream
import java.io.*;
public class RandomClass implements Serializable {
// Генерация рандомного значения
private static int r() {
return (int)(Math.random() * 10);
}
private int data[];
// Конструктор
public RandomClass() {
datafile = new int[r()];
for (int i=0; i<datafile.length; i++)
datafile[i]=r();
}
public void printout() {
System.out.println("This RandomClass has "+datafile.length+" random integers");
for (int i=0; i<datafile.length; i++) {
System.out.print(datafile[i]+":");
System.out.println();
}
}
No código acima, é criada uma classe que é serializável porque "marcado" pela interface de serialização. A classe cria uma matriz de inteiros aleatórios quando uma instância dela é criada. O código abaixo mostra a capacidade de gravar objetos em um fluxo usando o ObjectOutputStream
. O programa possui um array de números inteiros, mas para serialização não precisamos iterar sobre seus objetos internos. A interface Seriliazable
cuida disso automaticamente. Listagem 2. Um exemplo simples de serialização de objetos para saída em um arquivo
import java.io.*;
import java.util.*;
public class OutSerialize {
public static void main (String args[]) throws IOException {
RandomClass rc1 = new RandomClass();
RandomClass rc2 = new RandomClass();
//создание цепи потоков с потоком вывода an object в конце
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objects.dat"));
Date now = new Date(System.currentTimeMillis());
//java.util.* был импортирован для использования класса Date
out.writeObject(now);
out.writeObject(rc1);
out.writeObject(rc2);
out.close();
System.out.println("I have written:");
System.out.println("A Date object: "+now);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
O código abaixo demonstra os recursos da classe ObjectInputStream
, que lê dados serializados de um arquivo externo para um programa. Observe que os objetos são lidos na mesma ordem em que foram gravados no arquivo. Listagem 3. Lendo objetos serializados ou desserializando
import java.io.*;
import java.util.*;
public class InSerialize {
public static void main (String args[]) throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream (new FileInputStream("objects.dat"));
Date d1 = (Date)in.readObject();
RandomClass rc1 = (RandomClass)in.readObject();
RandomClass rc2 = (RandomClass)in.readObject();
System.out.println("I have read:");
System.out.println("A Date object: "+d1);
System.out.println("Two Group of randoms");
rc1.printout();
rc2.printout();
}
}
Quase todas as classes Java podem ser serializadas, incluindo classes AWT. Um quadro, que é uma janela, contém um conjunto de componentes gráficos. Se o quadro for serializado, o mecanismo de serialização cuida disso e serializa todos os seus componentes e dados (posição, conteúdo, etc.). Alguns objetos de classe Java não podem ser serializados porque contêm dados que fazem referência a recursos efêmeros do sistema operacional. Por exemplo classes java.io.FileInputStream
e java.lang.Thread
. Se um objeto contiver referências a elementos não serializáveis, toda a operação de serialização falhará e uma exceção será lançada NotSerializableException
. Se algum objeto se referir a uma referência de um objeto não serializado, ele poderá ser serializado usando a palavra-chave transitória . Listagem 4. Criando objetos serializáveis usando a palavra-chave transitória
public class Sclass implements Serializable{
public transient Thread newThread;
//помните, что поток(поток параллельного исполнения) по умолчанию не сериализуемый класс
private String studentID;
private int sum;
}
Segurança na serialização
Serializar uma classe em Java envolve passar todos os seus dados para um arquivo externo ou banco de dados por meio de um fluxo. Podemos limitar os dados que serão serializados sempre que desejarmos. Existem duas maneiras de fazer isso:- Cada parâmetro de classe declarado como transitório não é serializado (por padrão, todos os parâmetros de classe são serializados)
- Ou cada parâmetro da classe que queremos serializar é marcado com uma tag
Externalizable
(por padrão, nenhum parâmetro é serializado).
ObjectOutputStream
, quando chamado em um objeto, se o campo de dados desse objeto estiver marcado como transitório . Por exemplo: private transient String password
. Por outro lado, para declarar explicitamente os dados de um objeto como serializáveis, devemos marcar a classe como gravando e lendo ExternalizablewriteExternal
explicitamente readExteranl
os dados desse objeto.
Conclusão
O recurso de serialização de objetos é usado em muitos sistemas distribuídos como forma de transferir dados. Mas a serialização revela detalhes ocultos, destruindo assim a autenticidade dos tipos de dados abstratos, o que por sua vez destrói o encapsulamento. Ao mesmo tempo, é bom saber que os dados do objeto serializado são os mesmos dados que estavam no objeto original. Esta também é uma ótima oportunidade para implementar uma interfaceObjectInputValidation
e substituir um método validateObject()
, mesmo se várias linhas de código forem usadas. Se o objeto não for encontrado, podemos lançar uma exceção apropriadamente InvalidObjectException
. Artigo original: Como funciona a serialização em Java
GO TO FULL VERSION