Qual é o valor das variáveis estáticas após desserializar um objeto?
-
20-09-2019 - |
Pergunta
Digamos que eu crie uma instância da classe B, que possui uma variável estática x, atribuída com valor 3 na declaração da classe B.No método main(), eu faço isso:
B b = new B();
b.x = 7; //allowed to use an instance to set the static member value
Depois disso, b é serializado e então desserializado.Então ocorre a seguinte linha:
System.out.println ("static: " + b.x);
Qual é o valor?7 ou 3?
Eu sei que variáveis estáticas não são serializadas, entretanto, como há apenas uma cópia do membro estático para toda a classe e o valor está definido como 7, ele deve ser preservado após desserializar uma instância?
Solução
Aqui está o que acontece:
- O inicializador estático define o valor como 3.
- O construtor da instância define o valor como 7.
- A serialização não tem conhecimento da variável estática e é ignorada.
- A desserialização não tem conhecimento da variável estática e é ignorada.
- O valor ainda é 7 (da mudança que ocorreu no construtor) se o programa esteve em execução o tempo todo, ou se o programa foi encerrado e reiniciado, o inicializador estático o terá definido como 3 e a desserialização não o alterou.
Se você quiser a lógica descrita, precisará adicionar outra variável estática que conte o número de instâncias criadas e substitua a writeObject
e readObject
métodos com sua lógica personalizada.
Outras dicas
Se você desserializá-lo na mesma instância da JVM, seu segundo trecho retornará 7.Isso ocorre porque o valor de bx está definido como 7.Isso não mudou porque uma instância de B foi serializado e desserializado.
Se você serializar o objeto, encerrar a JVM, abrir uma nova JVM e, em seguida, desserializar o objeto (sem definir b.x em qualquer lugar que não seja a inicialização estática), o valor de b.x será 3.
Use o código a seguir para serializar e desserializar e objetar para/de um fluxo na memória:
package com.example.serialization;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import junit.framework.TestCase;
public class SerializationTest extends TestCase {
public void testStaticValueAfterSerialization() {
B b = new B();
b.x = 7; //allowed to use an instance to set the static member value
B deserializedB = copyObject(b);
assertEquals("b.x should be 7 after serialization", 7, deserializedB.x);
}
private <T extends Serializable> T copyObject(final T source) {
if (source == null)
throw new IllegalArgumentException("source is null");
final T copy;
try {
copy = serializationClone(source);
} catch (Exception e) {
// (optional) die gloriously!
throw new AssertionError("Error copying: " + source, e);
}
return copy;
}
private <T extends Serializable> T serializationClone(final T source)
throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream outputStream = new ObjectOutputStream(byteStream);
// 1. serialize the object to the in-memory output stream
outputStream.writeObject(source);
ObjectInputStream inputStream = new ObjectInputStream(
new ByteArrayInputStream(byteStream.toByteArray()));
// 2. deserialize the object from the in-memory input stream
@SuppressWarnings("unchecked")
final T copy = (T) inputStream.readObject();
return copy; // NOPMD : v. supra
}
}
Depois de criar essa classe, execute-a com um executor JUnit e veja se o teste passa!Se desejar, você pode gravar o resultado em um arquivo em um caso de teste.Então, em outro caso de teste, leia o resultado de um arquivo!
Como os inicializadores estáticos são executados exatamente uma vez, o valor é 7
.