Как сериализация Java десериализовывает заключительные поля, когда никакой конструктор по умолчанию не указал?

У меня есть класс, определяющий неизменный тип значения, который я теперь должен сериализировать. Неизменность прибывает из заключительных полей, которые установлены в конструкторе. Я попытался сериализировать, и это работает (удивительно?) - но я понятия не имею как.

Вот пример класса

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" предупреждение контроля для этого класса, все же успешно сгенерированные предупреждения для других классов, что я только что сделал сериализуемыми.)

49
задан amaidment 2 April 2014 в 04:09
поделиться

3 ответа

Десериализация реализуется JVM на уровне ниже основных конструкций языка. В частности, она не вызывает никаких конструкторов.

42
ответ дан 7 November 2019 в 11:48
поделиться

Учитывая, что класс не имеет конструктора no arg, как его можно инстанцировать и установить конечное поле?

Происходит какая-то неприятная черная магия. В JVM есть черный ход, который позволяет создать объект без вызова какого-либо конструктора. Поля нового объекта сначала инициализируются значениями по умолчанию (false, 0, null и т.д.), а затем код десериализации объекта заполняет поля значениями из потока объектов.

(Теперь, когда Java стала открытой, вы можете прочитать код, который это делает... и прослезиться!)

.
22
ответ дан 7 November 2019 в 11:48
поделиться

И Майкл, и Стивен дали вам отличный ответ, я просто хочу предупредить вас о переходных полях.

Если значение по умолчанию (null для ссылок, 0 для примитивов) неприемлемо для них после десериализации, то необходимо предоставить свою версию readObject и инициализировать ее там.

    private void readObject (
            final ObjectInputStream s
        ) throws
            ClassNotFoundException,
            IOException
    {
        s.defaultReadObject( );

        // derivedValue is still 0
        this.derivedValue = derivedValue( value );
    }
12
ответ дан 7 November 2019 в 11:48
поделиться
Другие вопросы по тегам:

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