views:

270

answers:

4

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?

+6  A: 

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.

Jared
+1 Same JVM or different JVM. Only thing that matters. b.x could be anything in a different JVM if the static initializer is changed between runs.
David Berger
+4  A: 

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.

Ben S
A: 

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

Aaron Digulla
just to let you know guys...according to Sun, the answer is 3.
Dan
No, it's not. Not unless there is something else going on in the code that you haven't shown.
Michael Borgwardt
Dan - can you provide a link to that Sun reference?
Jared
The serialisation/deserialisation is irrelevant if you read the question...
Tom Hawtin - tackline
Michael, you can believe what you want, that's coming from an e-practice exam for SCJP 6. I didn't write it
Dan
@Dan: Even Sun makes mistakes. Ask your instructor to prove his claim.
Aaron Digulla
I'd have to see the question from the practice exam. As my answer above states, the answer is 3, if and only if the static variable has been set to three somewhere else - serialization and deserialization of object instances have no effect on the current value of static variables.
Jared
+1  A: 

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!

LES2