Este artigo descreve a serialização do objeto e a desserialização em Java. Compartilhe para todos para sua referência. Os detalhes são os seguintes:
1. Introdução
A serialização do objeto refere -se ao processo de conversão de um objeto em uma sequência de bytes, enquanto a desserialização é o processo de restauração de um objeto baseado em uma sequência de bytes.
A serialização é geralmente usada nos seguintes cenários:
1. Salve o objeto permanentemente e salve a sequência de bytes do objeto no arquivo local;
2. Passe objetos na rede, serializando -os;
3. Passe objetos entre os processos através da serialização.
A classe à qual o objeto pertence deve implementar a interface serializável ou externizável a ser serializada. Para classes que implementam a interface serializável, a serialização e a deserivação adotam o método de serialização padrão.
Java.io.ObjectOutputStream representa o fluxo de saída do objeto, e seu método writeObject (objeto obj) pode realizar a serialização do objeto e escrever a sequência de bytes obtida no fluxo de saída de destino.
Java.io.ObjectInputStream representa o fluxo de entrada do objeto, e seu método readObject () pode ler uma sequência de bytes a partir do fluxo de entrada de origem, desesteri -o em um objeto e devolvê -lo.
2. Várias maneiras de serializar
Suponha que uma classe de cliente seja definida, dependendo do método de serialização do cliente, pode haver os seguintes métodos de serialização:
1. Implementar métodos serializáveis e indefinidos de readObject e writeObject
O ObjectOutputStream usa o JDK para serializar variáveis de instância não transitórios do objeto do cliente por padrão;
ObjectInputStream Desserializa variáveis de instância não transitórias do objeto do cliente usando o método padrão JDK.
2. Implementar métodos serializáveis e definir readObject e WriteObject
ObjectOutputStream chama o método WriteObject (ObjectOutputStream) da classe do cliente para serializar variáveis de instância não transitíveis do objeto do cliente;
ObjectInputStream chama o método readObject (objectInputStream in) da classe do cliente para desserializar variáveis de instância não transitórias do objeto do cliente.
3. Implemente os métodos externos, definem readExternal e WriteExternal
ObjectOutputStream chama o método WriteExternal da classe do cliente para serializar variáveis de instância não transitíveis do objeto do cliente;
O ObjectInputStream primeiro instancia um objeto através do construtor sem parâmetros da classe do cliente e, em seguida, desaperializa a variável de instância não transitória do objeto do cliente usando o método ReadExternal.
3. Interface serializável
A classe permite sua funcionalidade de serialização implementando a interface java.io.Serializable. As classes que não implementam essa interface não serão capazes de serializar ou desserializar nenhum de seus estados. Todos os subtipos de uma classe serializável são eles mesmos serializáveis. A interface de serialização não possui métodos ou campos e é usada apenas para identificar a semântica serializável.
Durante o processo de deserialização, os campos da classe não serrializada serão inicializados usando o construtor comum ou protegido sem parâmetros da classe. A subclasse serializável deve poder acessar o construtor sem parâmetros. Os campos que podem ser subclasses serializáveis serão restaurados do fluxo.
Ao atravessar uma visualização de classe, você pode encontrar objetos que não suportam a interface serializável. Nesse caso, é identificada uma não -renda e a classe que não é serializável é identificada.
1. Assinatura precisa
As classes que requerem processamento especial durante a serialização e a desserialização devem implementar métodos especiais usando as seguintes assinaturas precisas:
Private Void WriteObject (java.io.ObjectOutputStream Out) lança a ioexception
private void readObject (java.io.ObjectInputStream in) lança IoException, ClassNotFoundException;
private void readObjectNodata () lança objectStreamException;
O método WriteObject é responsável por escrever o estado de um objeto de uma classe específica, para que o método readObject correspondente possa restaurá -lo. O mecanismo padrão para salvar os campos do objeto pode ser chamado ligando.DefaultWriteObject. O próprio método não precisa envolver estados pertencentes à sua superclasse ou subclasse. O estado pode ser salvo escrevendo campos individuais no objectOutputStream usando o método WriteObject ou usando o método suportado pelo DataOutput para tipos de dados básicos.
O método ReadObject é responsável pela leitura e restauração dos campos de classe do fluxo. Ele pode ligar para o in.defaultreadObject para chamar o mecanismo padrão para restaurar campos não estáticos e não transitórios do objeto. O método DefaultretoBject usa informações no fluxo para alocar campos de objetos no fluxo que são salvos através dos campos especificados correspondentes no objeto atual. Isso é usado para lidar com situações em que novos campos precisam ser adicionados após a evolução da classe. O próprio método não precisa envolver estados pertencentes à sua superclasse ou subclasse. O estado pode ser salvo escrevendo campos individuais no objectOutputStream usando o método WriteObject ou usando o método suportado pelo DataOutput para tipos de dados básicos.
No caso em que o fluxo de serialização não liste a classe fornecida como a superclasse a ser desserializada, o método ReadObjectNodata é responsável por inicializar o estado de objeto de uma classe específica. Isso ocorre quando a classe de instância desserializada usada pelo receptor é diferente do remetente e a classe estendida pela versão do receptor não é uma classe estendida pela versão do remetente. Também ocorre quando o fluxo de serialização foi adulterado;
Ao escrever objetos em um fluxo, você precisa especificar a classe serializável do objeto alternativo a ser usado e deve implementar esse método especial com uma assinatura precisa:
Objeto de qualquer modelo de acesso Writereplace () lança objectStreamException;
Esse método WritEreplace será chamado por serialização, desde que exista esse método e possa ser acessado por um método definido na classe do objeto serializado. Portanto, o método pode ter acesso privado, protegido e privado de pacotes. O acesso da subclasse a esse método segue as regras de acesso Java.
Ao ler uma instância de uma classe a partir de um fluxo, você precisa especificar a assinatura exata que a classe alternativa deve usar para implementar esse método especial.
Qualquer objeto de qualquer acesso de acesso readResolve () lança ObjectStreamException;
Esse método ReadResolve segue as mesmas regras de chamada e regras de acesso que o WritEreplace.
Se uma classe definir um método readResolve, o método readResolve será chamado no final da deserivação, e o objeto retornado pelo método é o resultado final da desertalização.
2.SerialversionUid
O tempo de execução da serialização usa um número de versão chamado SerialVersionUID para se associar a cada classe serializável, usada durante a desserialização para verificar se o remetente e o destinatário do objeto serializado carregado para o objeto. Se o receptor carregar o serialversionUid da classe do objeto diferente do número da versão do remetente correspondente, a deserialização resultará em uma concepção invalidada. Uma classe serializável pode declarar explicitamente seu próprio serialversionuid declarando um campo chamado "SerialversionUid" (esse campo deve ser um campo estático e final):
Qualquer alma de qualquer acesso estático de longa serialversionuid = 42L;
Se a classe serializável não declarar explicitamente serialversionuid, o tempo de execução da serialização calcula o valor de serialversionUid padrão da classe com base em vários aspectos da classe, conforme descrito na especificação de serialização do objeto "Java (TM)". No entanto, é altamente recomendável que todas as classes serializáveis declarem explicitamente os valores SerialversionUid, porque o cálculo do serialversion padrão é altamente sensível aos detalhes da classe e pode variar muito, dependendo da implementação do compilador, portanto, no processo de deseralização, uma invalidação inesperada pode resultar. Portanto, para garantir a consistência entre os valores de serialversionuid entre diferentes compiladores Java, a classe serializada deve declarar um valor explícito de serialversionuid. Também é altamente recomendável usar o modificador privado para exibir a declaração serialversionUid, se possível, porque essas declarações são usadas apenas para declarar diretamente a classe - o campo SerialversionUid como membro herdado não tem utilidade. As classes de matriz não podem declarar um serialversion explícito, portanto, sempre têm o valor calculado padrão, mas as classes de matriz não correspondem aos requisitos de valor serialversionUID.
3. Externiza Interface
Externizable é uma extensão do seriabrastável.
Chame o método da classe WriteExternal durante a serialização e desserialize o método ReadExternal;
Ao executar a desserialização, o construtor sem parâmetros da classe é chamado primeiro, o que é diferente da desserialização padrão.
Quarto, resumo
Se o método de serialização padrão for adotado, desde que uma classe implemente a interface serializável, sua instância poderá ser serializada. Geralmente, as classes projetadas especificamente para herança devem tentar não implementar a interface serializável, porque uma vez que a classe pai implementa a interface serializável, todas as suas subclasses são serializáveis.
As deficiências do método de serialização padrão:
1. Não é seguro serializar diretamente dados sensíveis que não são adequados para a divulgação do objeto;
2. Não verificará se as variáveis do membro do objeto atendem às restrições corretas e podem ser adulteradas com os dados e causar operação anormal;
3. A travessia recursiva do gráfico de objeto é necessária.
4. Faça a interface da classe restringida pela implementação interna da classe, restringindo a atualização e a manutenção da classe.
Implementando o tipo privado writeObject () e readObject () da interface serializável ou implementando a interface externizável, implementando os métodos WriteExternal () e ReadExternal () e fornecendo um construtor sem parâmetros do tipo público duas maneiras de controlar o processo de serialização que ele pode efetivamente evitar as deficiências do método de serialização padrão.
Espera -se que este artigo seja útil para o design do programa Java de todos.