Сериализация открытых финальных полей - PullRequest
1 голос
/ 30 октября 2011

Я использую простую структуру, в которой я храню значения только для чтения (например, свойства без установщика в C #).Для этого я использую public final int test=42;.

. По некоторым причинам я хочу разрешить сериализацию этого класса.Я использую этот код:

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.writeInt(test);
}
private void readObject(ObjectInputStream ois) throws IOException {
    test=ois.readInt();
}

Последний не работает, потому что полевой тест является окончательным, как я могу решить эту проблему?

Ответы [ 4 ]

2 голосов
/ 30 октября 2011

readObject всегда должен начинаться с defaultReadObject или readFields; writeObject с defaultWriteObject или putFields. defaultReadObject установит для вас поле final.

Если вы хотите использовать readFields, либо удалите final, либо спрячьте во временное поле и внедрите readResolve (обратите внимание, что оригинальный объект все еще будет доступен заинтересованным сторонам). Как правило, вы действительно не хотите прибегать к таким sun.misc.Unsafe.

(Новая модель памяти Java (JMM), представленная в J2SE 5.0 (и реализованная в JDK 1.4), дает больше возможностей в способе оптимизации конечного поля. В примере кода вопроса поле инициализируется с помощью выражение постоянной времени компиляции выражение. Таким образом, я ожидаю, что оно будет встроенным (не проверено).)

0 голосов
/ 30 октября 2011

Меняется ли значение этого поля final для каждого объекта или оно одинаково для всех объектов?т.е. он установлен на уровне конструктора или объявления поля?Если он останется прежним, простейшим решением будет сделать его static и избавиться от дополнительных затрат на чтение и запись значений «только для чтения».Кроме того, обязательно ли вам предоставлять реализации readObject и writeObject вместо того, чтобы полагаться на механизм по умолчанию?

0 голосов
/ 30 октября 2011

Вы можете использовать отражение, чтобы изменить значение test

// Get the Class object for the class of which test is a field
Class<?> myClass = MyClass.class;

// We will need to set test as accessible so as to change it's value
// Get the Field object for test
Field testField = myClass.getDeclaredField("test");
// Save the current accessibility of test
boolean wasAccessible = testField.isAccessible();
// Mark test as accessible
testField.setAccessible(true);
// Set the value of test for this instance of MyClass
int newTestValue = 42;
testField.setInt(this, newTestValue);
// Restore the accesibility of test to it's original
testField.setAccessible(wasAccessible);

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

0 голосов
/ 30 октября 2011

во-первых, примитивную константу public final можно сделать public static final, и ее не нужно сериализовать, потому что ее всегда одно и то же значение.

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

int test=ois.readInt();
Field testField = getClass().getDeclaredField("test");
testField.setAccessible(true);
testField.set(this, test);

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...