简体   繁体   中英

How to serialize static data members of a Java class?

When we serialize objects, static members are not serialized, but if we need to do so, is there any way out?

The first question is why you need to serialize the static members?

Static members are associated with the class, not the instances, so it does not make sense to include them when serializing an instance.

The first solution is to make those members not static. Or, if those members are the same in the original class and the target class (same class, but possibly different runtime environments), don't serialize them at all.

I have a few thoughts on how one could send across static members, but I first need to see the use case, as in all cases that means updating the target class, and I haven't found a good reason to do so.

Folks, static doesn't mean IMMUTABLE. For instance, I may want to serialize the whole state of the computation (yes, including static fields -- counters, etc) to resume later, after JVM and/or host computer restarted.

The right answer to that, as already said, is to use Externalizable, not Serializable, interface. Then you have a complete control on what and how you externalize.

This is serialization for the static field: newBookingNumber.

class Booking implements Serializable
{

    /**
     * Generated serial version ID.
     */

    private static final long serialVersionUID = 5316748056989930874L;

    // To hold new booking number.
    private static int newBookingNumber = 0;

    // The booking number.
    private int bookingNumber;


    /* 
     * Default serializable fields of a class are defined to be 
     * the non-transient and non-static fields. So, we have to 
     * write and read the static field separately.
     */
    private void writeObject(ObjectOutputStream oos)
        throws IOException 
    {
        oos.defaultWriteObject();
        oos.writeObject(new Integer(newBookingNumber));
    }

    private void readObject(ObjectInputStream ois)
    throws ClassNotFoundException, IOException 
    {
        ois.defaultReadObject();
        newBookingNumber = (Integer)ois.readObject();
    }
}

You can control serialization by implementing:

private void writeObject(ObjectOutputStream out) throws IOException;

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

There's a full description of serialization http://java.sun.com/developer/technicalArticles/Programming/serialization/ .

As other answers have said, it doesn't really make sense to serialize statics as it's the object not the class you're serializing and needing to do so smells like you've got other issues with your code to me.

Good answers and comments--don't do it. But how?

Chances are you would be best off creating an object to hold all your "Statics". That object should probably have any static methods from your class as well.

Every instance of your class can hold this other class--or if you really have to you can make it a singleton that any member can access.

After you do this refactor, you will find that it should have been done this way all along. You may even find that some of your previous design constraints that were bothering you at a subconsicionce level have vanished.

You'll probably find that this solution also solves other Serialization problems you hadn't even noticed yet.

You can do this without having to manually update your class every time you simply change a field. You may want to do this if you want to have the ease of static members for access to settings in an application, but would also like to save those settings. In this case, you would also want to have the option to apply them at whim, not load by default as the other solutions here necessitate, since they are static. This allows for rollback of settings for obvious reasons.

Basically, use the field methods to get all the members in the class, then map the full names of these fields to the contents. The full name is required since Field is not serializable itself. Serialize this mapping, and reinstate it to get the saved settings.

The second part of the puzzle is the apply() type of function. This goes thru the mapping, and applies what it can to the static class.

You must also ensure that the contents of the static members are themselves serializable.

As can hopefully be seen from this example class, the static members can easily be saved and returned. I'll leave it up to the implementer to worry about UIDs of classes, safeguards etc. isSameAs() is used for unit testing. AppSettings is the class that contains all the static fields that you wish to serialize.

public class AppSettingsReflectorSaver implements Serializable {

HashMap<String, Object> genericNamesAndContents = new HashMap<String, Object>();
private AppSettingsReflectorSaver() {
}

static AppSettingsReflectorSaver createAppSettingsSaver() {
    AppSettingsReflectorSaver ret = new AppSettingsReflectorSaver();
    ret.copyAppSettings();
    return ret;
}

private void copyAppSettings() {
    Field[] fields = AppSettings.class.getFields();
    for (Field field : fields) {
        mapContentsForSerialization(field);
    }
}

private void mapContentsForSerialization(Field field) {
    try {
        Object fieldContents = field.get(AppSettings.class);
        genericNamesAndContents.put(field.toGenericString(), fieldContents);
    } catch (IllegalArgumentException ex) {
        Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
    }
}

boolean isSameAs(AppSettingsReflectorSaver now) {
    for( String thisKey : genericNamesAndContents.keySet()){
        boolean otherHasThisKey = now.genericNamesAndContents.containsKey(thisKey);
        Object thisObject = genericNamesAndContents.get(thisKey);
        Object otherObject = now.genericNamesAndContents.get(thisKey);
        boolean otherHasThisValue = thisObject.equals(otherObject);
        if (!otherHasThisKey || !otherHasThisValue){
            return false;
        }
    }
    return true;
}

void applySavedSettingsToStatic() {
    Field[] fields = AppSettings.class.getFields();
    for (Field field : fields) {
        if (!genericNamesAndContents.containsKey(field.toGenericString())){
            continue;
        }
        Object content = genericNamesAndContents.get(field.toGenericString() );
        try {
            field.set(AppSettings.class, content);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

}

This is my first post - go easy on me:P~

Static members belong to the class, not to the individual objects.

You should reconsider your data structure.

Yes, we can serialize the static variables. But we can write our own writeObject() and readObject() . I think this can solve the problem.

To have compact implementation, implement readObject & writeObject in your class call defaultReadObject & defaultWriteObject methods within those methods which handles normal serialization and then proceed with serializing & de-serializing whatever additional fields you need.

Regards, GK

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM