Question

Let's say that I create an instance of class B, which has an static variable x, assigned with a value of 3 in the class B declaration. In the main() method, I do this:

B b = new B();
b.x = 7; //allowed to use an instance to set the static member value

After this, b is serialized and then de-serialized. Then, the following line occurs:

System.out.println ("static: " + b.x);

What's the value? 7 or 3?

I know static variables are not serialized, however, since there is only one copy of the static member for the whole class, and the value is set to 7, should it be preserved after de-serializing an instance?

Was it helpful?

Solution

Here's what happens:

  1. Static initializer sets the value to 3.
  2. Instance constructor sets the value to 7.
  3. Serialization is unaware of the static variable and it is ignored.
  4. De-serialization is unaware of static variable and it is ignored.
  5. Value is still 7 (from the change that occurred in the constructor) if the program has been running all along, or if the program was shutdown and restarted, the static initializer will have set it to 3 and de-serialization did not change it.

If you want the logic you describe, you need to add another static variable which counts the number of instances created and override the writeObject and readObject methods with your custom logic.

OTHER TIPS

If you deserialize it in the same instance of the JVM, your second snippet will return 7. This is because the value of b.x is set to 7. That hasn't changed because an instance of B was serialized and deserialized.

If you serialize the object, shutdown the JVM, bring up a new JVM, and then deserialize the object (without setting b.x anywhere other than the static initialization), the value of b.x will be 3.

Use the following code to serialize and deserialize and object to / from an in-memory stream:

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
    }
}

After creating that class, run it with a JUnit runner and see if the test passes! If you like, you can write the result to a file in one test case. Then in another test case, read the result from a file!

Since static initializers run exactly once, the value is 7.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top