Как сериализовать статические члены данных класса Java?

когда мы сериализуем объекты, статические члены не сериализуются, но если нам нужно это сделать, есть ли выход?

9 ответов


первый вопрос: почему вам нужно сериализовать статические члены?

статические члены связаны с классом, а не экземплярами, поэтому нет смысла включать их при сериализации экземпляра.

первое решение-сделать эти члены не статичными. Или, если эти члены одинаковы в исходном классе и целевом классе (тот же класс, но, возможно, разные среды выполнения), не сериализуйте их вообще.

У меня есть мало мыслей о том, как можно отправлять статические члены, но сначала мне нужно увидеть вариант использования, так как во всех случаях это означает обновление целевого класса, и я не нашел веской причины для этого.


люди, статика не означает неизменяемость. Например, я могу захотеть сериализовать все состояние вычисления (да, включая статические поля -- счетчики и т. д.), Чтобы возобновить позже, после перезапуска JVM и/или хост-компьютера.

правильный ответ на это, как уже было сказано, заключается в использовании Externalizable, а не Serializable, interface. Тогда у вас есть полный контроль, что и как ты воплощаешь.


вы можете управлять сериализацией по реализации:

private void writeObject(ObjectOutputStream out) throws IOException;

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

существует полное описание сериализации http://java.sun.com/developer/technicalArticles/Programming/serialization/.

Как говорили другие ответы, на самом деле не имеет смысла сериализовать статику, поскольку это объект, а не класс, который вы сериализуете, и это пахнет так, как у вас есть другие проблемы с вашим кодом для меня.


это сериализация для статического поля: 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();
    }
}

хорошие ответы и комментарии--не делай этого. Но как?

скорее всего, вам лучше всего создать объект, чтобы держать все ваши "статики". Этот объект, вероятно, должен иметь любые статические методы из вашего класса.

каждый экземпляр вашего класса может содержать этот другой класс-или, если вам действительно нужно, вы можете сделать его синглтоном, к которому может получить доступ любой член.

после того, как вы сделаете этот рефакторинг, вы обнаружите, что это должно было быть сделано таким образом все вдоль. Вы даже можете обнаружить, что некоторые из ваших предыдущих ограничений дизайна, которые беспокоили вас на подсознательном уровне, исчезли.

вероятно, вы обнаружите, что это решение также решает другие проблемы сериализации, которые вы еще не заметили.


вы можете сделать это без необходимости вручную обновлять свой класс каждый раз, когда вы просто измените поле. Вы можете сделать это, если хотите иметь простоту статических членов для доступа к настройкам в приложении, но также хотите сохранить эти настройки. В этом случае вы также хотите иметь возможность применять их по прихоти, а не загружать по умолчанию, как это требуется для других решений, поскольку они статичны. Это позволяет откат настроек для очевидного причины.

в основном используйте методы field для получения всех членов класса, а затем сопоставьте полные имена этих полей содержимому. Полное имя является обязательным, так как поле само по себе не сериализуемо. Сериализуйте это сопоставление и восстановите его, чтобы получить сохраненные настройки.

вторая часть головоломки-это тип функции apply (). Это проходит через сопоставление и применяет все, что может, к статическому классу.

вы также должны убедиться, что содержимое сами статические члены сериализуемы.

Как надеюсь видно из этого примера класса, статические члены могут быть легко сохранены и возвращены. Я оставлю это на реализацию, чтобы беспокоиться о UIDs классов, гарантий и т. д. isSameAs () используется для модульного тестирования. AppSettings-это класс, содержащий все статические поля, которые необходимо сериализовать.

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

}

Это мой первый пост - go easy on me: P~


статические члены принадлежат классу, а не отдельным объектам.

вы должны пересмотреть свои структуры данных.


чтобы иметь компактную реализацию, реализуйте readObject & writeObject в своем классе вызовите методы defaultReadObject & defaultWriteObject в тех методах, которые обрабатывают обычную сериализацию, а затем продолжите сериализацию и де-сериализацию любых дополнительных полей, которые вам нужны.

с уважением, GK


Да, мы можем сериализовать статические переменные. Но мы можем написать наши собственные writeObject() и readObject(). Думаю, это может решить проблему.