Вопрос по java – Как сериализовать статические данные членов класса Java?

29

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

Никогда не имеет смысла говорить "никогда". Vladimir Dyuzhev
Владимир, нет смысла сериализовать статические поля. Tom Hawtin - tackline
Прекратить использовать статические члены для данных, которые должны быть сериализованы? krosenvold
Addendum: прекратить использование статических членов для хранения изменяемого состояния. Juliet
Shared и mutable не являются взаимоисключающими. Не имеет смысла сериализовать статические константы (потому что они неизменяемы), но иногда имеет смысл сериализовать статические переменные (потому что они должны быть синхронизированы с остальной частью состояния при десериализации). Vladimir Dyuzhev

Ваш Ответ

9   ответов
18

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

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

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

Предположим, я хочу посчитать количество экземпляров класса, как автомобиль. и я не использую базу данных. Так что в этом случае после закрытия приложения мне нужно хранить эту информацию с другой информацией. Maddy.Shik
Вам нужно хранить этот номер напрямую? Если вы обновите номер при десериализации каждого автомобиля (переопределив readObject), он будет правильно отражать количество автомобилей в сериализации. Kathy Van Stone
еременная @Static совместно используется всеми экземплярами объектов класса (разделяемая память). Если вам нужно сохранить что-то статическое, например, позволяет иметь перечисление различных значений, и время от времени вы будете изменять статическое значение этого типа перечисления, изменение сохраненного значения может быть таким же простым, как если бы все классы установили локальную переменную к этому типу. Или вы могли бы сделать еще один шаг, и группа классов расширила бы класс Wh независимо, а класс Wh могли бы просто предоставить локальную переменную всем своим дочерним элементам. Когда вы десериализуете, вы можете перезагрузить ваши статические значения обратно, как они были. user1043000
15

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

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

Изменяемая статика обычно означает «не работает». Tom Hawtin - tackline
Да. Сделай это синглтоном. Сериализировать синглтон. Или, лучше, избавиться от общего статического хранилища, сохранить его в явном объекте контекста. Thilo
Если состояние вычисления не встроено в объект, который вы сериализуете, вам не следует хранить его как часть сериализации этого объекта. DJClayworth
Подумай еще раз. Как насчет многопоточных генетических алгоритмов, например? Общее (статическое) хранилище используется для ведения реестра оцененных вариантов. Сделать это синглтон? Возможно, но у него есть свои недостатки. Vladimir Dyuzhev
... А потом еще одна группа пуристов будет жаловаться, что синглтон - это анти-паттерн, и мне тоже следует от него избавиться. Что касается «явного объекта контекста», как разные потоки получают к нему доступ? С помощью статических методов? Как лучше? Vladimir Dyuzhev
0

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

Regards, GK

5

private void writeObject(ObjectOutputStream out) throws IOException;

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

Там есть полное описание сериализацииhttp: //java.sun.com/developer/technicalArticles/Programming/serialization.

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

Так как мы не знаем контекст, мы не можем сказать, имеет ли он смысл или нет. Например, после использования сериализации по умолчанию может иметь смысл добавить статический член в поток. При десериализации можно установить статический член, если он равен нулю, иначе отбросить сериализованный объект. erickson
Том, ты злоупотребляешь "доказательством за повторением", не так ли? ;) Vladimir Dyuzhev
Вы можете контролировать сериализацию, но нет смысла помещать статические данные, потому что это не имеет никакого смысла в контексте. Tom Hawtin - tackline
есть ли выход для сериализации статических членов путем сериализации Class Object для моего класса. Maddy.Shik
1

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

0

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

5

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

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

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

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

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

Как можно надеяться, видно из этого примера класса, статические члены могут быть легко сохранены и возвращены. Я оставлю это на усмотрение разработчика, чтобы он беспокоился об идентификаторах UID классов, мерах защиты и т. Д. 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);
        }
    }
}

}

Это мой первый пост - будь осторожен со мной: P ~

2

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

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

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

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

Похожие вопросы