Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

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

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

Ответ 2

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

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

Ответ 3

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

private void writeObject(ObjectOutputStream out) throws IOException;

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

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

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

Ответ 4

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

Ответ 5

Статические члены относятся к классу, а не к отдельным объектам.

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

Ответ 6

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

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

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

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

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

Ответ 7

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

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

Вторая часть головоломки - это тип функции 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 ~

Ответ 8

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

Ответ 9

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

С уважением, ГК