O livro Java Efetivo e outras fontes fornecem uma boa explicação sobre como e quando usar o método readObject () ao trabalhar com classes Java serializáveis. O método readResolve (), por outro lado, permanece um pouco misterioso. Basicamente, todos os documentos que encontrei mencionam apenas um dos dois ou mencionam os dois apenas individualmente.
As perguntas que permanecem sem resposta são:
- Qual é a diferença entre os dois métodos?
- Quando qual método deve ser implementado?
- Como readResolve () deve ser usado, especialmente em termos de retorno de quê?
Espero que você possa lançar alguma luz sobre este assunto.
java
serialization
singleton
Forragem
fonte
fonte
String.CaseInsensitiveComparator.readResolve()
Respostas:
readResolve
é usado para substituir o objeto lido do fluxo. O único uso que eu já vi para isso é impor singletons; quando um objeto for lido, substitua-o pela instância singleton. Isso garante que ninguém possa criar outra instância serializando e desserializando o singleton.fonte
transient
campos.readResolve
é usado para resolver o objeto depois que ele é lido. Um exemplo de uso é talvez um objeto que armazene algum cache que possa ser recriado a partir de dados existentes e não precise ser serializado; os dados em cache podem ser declaradostransient
ereadResolve()
podem reconstruí-los após a desserialização. Coisas assim são para que serve esse método.Serializable
: ele diz "Classes que precisam designar uma substituição quando uma instância dela é lida a partir do fluxo devem implementar este [readResolve
] método especial ...".O item 90, Java efetivo, 3ª Ed, cobre
readResolve
ewriteReplace
para proxies seriais - seu principal uso. Os exemplos não escrevemreadObject
ewriteObject
métodos porque estão usando serialização padrão para ler e gravar campos.readResolve
é chamado depoisreadObject
que retornou (inversamentewriteReplace
é chamado anteswriteObject
e provavelmente em um objeto diferente). O objeto que o método retorna substitui othis
objeto retornado ao usuárioObjectInputStream.readObject
e quaisquer outras referências anteriores ao objeto no fluxo. AmbosreadResolve
ewriteReplace
podem retornar objetos do mesmo ou de tipos diferentes. Retornar o mesmo tipo é útil em alguns casos em que os campos devem estarfinal
e a compatibilidade com versões anteriores é necessária ou os valores devem ser copiados e / ou validados.O uso de
readResolve
não impõe a propriedade singleton.fonte
readResolve pode ser usado para alterar os dados que são serializados através do método readObject. Por exemplo, a API xstream usa esse recurso para inicializar alguns atributos que não estavam no XML a serem desserializados.
http://x-stream.github.io/faq.html#Serialization
fonte
readResolve é para quando você precisar retornar um objeto existente, por exemplo, porque você está verificando entradas duplicadas que devem ser mescladas ou (por exemplo, em sistemas distribuídos eventualmente consistentes), porque é uma atualização que pode chegar antes que você esteja ciente de quaisquer versões mais antigas.
fonte
readObject () é um método existente na classe ObjectInputStream. enquanto lê o objeto no momento da desserialização, o método readObject verifica internamente se o objeto de classe que está sendo desserializado com o método readResolve ou se o método readResolve existe, então ele invocará o método readResolve e retornará o mesmo instância.
Portanto, a intenção de escrever o método readResolve é uma boa prática para atingir o padrão de design singleton puro, onde ninguém pode obter outra instância serializando / desserializando.
fonte
readResolve () garantirá o contrato de singleton durante a serialização.
Por favor consulte
fonte
Quando a serialização é usada para converter um objeto para que ele possa ser salvo em arquivo, podemos acionar um método, readResolve (). O método é privado e é mantido na mesma classe cujo objeto está sendo recuperado durante a desserialização. Ele garante que, após a desserialização, qual objeto retornado seja o mesmo que foi serializado. Isso é,
instanceSer.hashCode() == instanceDeSer.hashCode()
O método readResolve () não é estático. After
in.readObject()
é chamado durante a desserialização, apenas garante que o objeto retornado seja o mesmo que foi serializado como abaixo enquantoout.writeObject(instanceSer)
Dessa maneira, também ajuda na implementação do padrão de design de singleton , porque sempre que a mesma instância é retornada.
fonte
Sei que essa pergunta é realmente antiga e tem uma resposta aceita, mas, como aparece muito na pesquisa do Google, pensei em pesar porque nenhuma resposta fornecida cobre os três casos que considero importantes - na minha opinião, o principal uso desses métodos. Obviamente, todos assumem que há realmente uma necessidade de formato de serialização personalizado.
Tome, por exemplo, classes de coleção. A serialização padrão de uma lista vinculada ou de um BST resultaria em uma enorme perda de espaço com muito pouco ganho de desempenho em comparação com apenas a serialização dos elementos em ordem. Isso é ainda mais verdadeiro se uma coleção é uma projeção ou uma exibição - mantém uma referência a uma estrutura maior do que expõe por sua API pública.
Se o objeto serializado tiver campos imutáveis que precisam de serialização personalizada, a solução original de
writeObject/readObject
é insuficiente, pois o objeto desserializado é criado antes de ler a parte do fluxo gravadawriteObject
. Tome esta implementação mínima de uma lista vinculada:Essa estrutura pode ser serializada escrevendo recursivamente o
head
campo de cada link, seguido por umnull
valor. A desserialização de um formato desse tipo se torna impossível:readObject
não é possível alterar os valores dos campos dos membros (agora fixados emnull
). Aí vem o parwriteReplace
/readResolve
:Lamento se o exemplo acima não compila (ou funciona), mas espero que seja suficiente para ilustrar meu argumento. Se você acha que este é um exemplo muito abrangente, lembre-se de que muitas linguagens funcionais são executadas na JVM e essa abordagem se torna essencial no caso deles.
Podemos querer realmente desserializar um objeto de uma classe diferente da que escrevemos para o
ObjectOutputStream
. Este seria o caso de visualizações como umajava.util.List
implementação de lista que expõe uma fatia de uma mais longaArrayList
. Obviamente, serializar toda a lista de apoio é uma má idéia e devemos escrever apenas os elementos da fatia exibida. Por que parar com isso e ter um nível inútil de indireção após a desserialização? Poderíamos simplesmente ler os elementos do fluxo em umArrayList
e retorná-lo diretamente, em vez de agrupá-lo em nossa classe view.Como alternativa, ter uma classe delegada semelhante dedicada à serialização pode ser uma opção de design. Um bom exemplo seria reutilizar nosso código de serialização. Por exemplo, se tivermos uma classe de construtor (semelhante ao StringBuilder para String), podemos escrever um delegado de serialização que serialize qualquer coleção gravando um construtor vazio no fluxo, seguido pelo tamanho da coleção e pelos elementos retornados pelo iterador da coleção. A desserialização envolveria a leitura do construtor, o acréscimo de todos os elementos de leitura subsequentes e o retorno do resultado final
build()
dos delegadosreadResolve
. Nesse caso, precisaríamos implementar a serialização apenas na classe raiz da hierarquia de coleções, e nenhum código adicional seria necessário para implementações atuais ou futuras, desde que implementassem o resumoiterator()
ebuilder()
método (o último para recriar a coleção do mesmo tipo - o que seria um recurso muito útil por si só). Outro exemplo seria ter uma hierarquia de classes cujo código não controlamos totalmente - nossa (s) classe (s) base (s) de uma biblioteca de terceiros podem ter qualquer número de campos particulares que não sabemos nada sobre o qual podemos mudar de uma versão para outra, quebrando nossos objetos serializados. Nesse caso, seria mais seguro gravar os dados e reconstruir o objeto manualmente na desserialização.fonte
O método readResolve
Para as classes Serializable e Externalizable, o método readResolve permite que uma classe substitua / resolva o objeto lido do fluxo antes de retornar ao chamador. Ao implementar o método readResolve, uma classe pode controlar diretamente os tipos e instâncias de suas próprias instâncias sendo desserializadas. O método é definido da seguinte maneira:
QUALQUER ACESSO-MODIFICADOR O objeto readResolve () lança ObjectStreamException;
O método readResolve é chamado quando ObjectInputStream lê um objeto do fluxo e está se preparando para devolvê-lo ao chamador. ObjectInputStream verifica se a classe do objeto define o método readResolve. Se o método for definido, o método readResolve será chamado para permitir que o objeto no fluxo designe o objeto a ser retornado. O objeto retornado deve ser de um tipo compatível com todos os usos. Se não for compatível, uma ClassCastException será lançada quando a incompatibilidade de tipo for descoberta.
Por exemplo, uma classe Symbol pode ser criada para a qual existia apenas uma instância de cada ligação de símbolo em uma máquina virtual. O método readResolve seria implementado para determinar se esse símbolo já foi definido e substituir o objeto Symbol equivalente preexistente para manter a restrição de identidade. Dessa maneira, a exclusividade dos objetos Symbol pode ser mantida na serialização.
fonte
Como já foi respondido,
readResolve
é um método privado usado no ObjectInputStream ao desserializar um objeto. Isso é chamado antes do retorno da instância real. No caso de Singleton, aqui podemos forçar o retorno de referência de instância singleton já existente, em vez de referência de instância desserializada. Temos o mesmowriteReplace
para ObjectOutputStream.Exemplo para
readResolve
:}
Resultado:
fonte