У меня есть класс, определяющий неизменный тип значения, который я теперь должен сериализировать. Неизменность прибывает из заключительных полей, которые установлены в конструкторе. Я попытался сериализировать, и это работает (удивительно?) - но я понятия не имею как.
Вот пример класса
public class MyValueType implements Serializable
{
private final int value;
private transient int derivedValue;
public MyValueType(int value)
{
this.value = value;
this.derivedValue = derivedValue(value);
}
// getters etc...
}
Учитывая, что класс не имеет никакого конструктора аргумента, как он можно инстанцировать и заключительный полевой набор?
(В стороне - я заметил этот класс особенно, потому что ИДЕЯ не генерировала "serialVersionUID" предупреждение контроля для этого класса, все же успешно сгенерированные предупреждения для других классов, что я только что сделал сериализуемыми.)
Десериализация реализуется JVM на уровне ниже основных конструкций языка. В частности, она не вызывает никаких конструкторов.
Учитывая, что класс не имеет конструктора no arg, как его можно инстанцировать и установить конечное поле?
Происходит какая-то неприятная черная магия. В JVM есть черный ход, который позволяет создать объект без вызова какого-либо конструктора. Поля нового объекта сначала инициализируются значениями по умолчанию (false, 0, null и т.д.), а затем код десериализации объекта заполняет поля значениями из потока объектов.
(Теперь, когда Java стала открытой, вы можете прочитать код, который это делает... и прослезиться!)
. И Майкл, и Стивен дали вам отличный ответ, я просто хочу предупредить вас о переходных
полях.
Если значение по умолчанию (null
для ссылок, 0 для примитивов) неприемлемо для них после десериализации, то необходимо предоставить свою версию readObject
и инициализировать ее там.
private void readObject (
final ObjectInputStream s
) throws
ClassNotFoundException,
IOException
{
s.defaultReadObject( );
// derivedValue is still 0
this.derivedValue = derivedValue( value );
}