Java: почему десериализация не вызывает конструктор и каков лучший обходной путь? - PullRequest
16 голосов
/ 22 августа 2011

Спецификация Java-сериализации для Java 1.5 сообщает:

Для сериализуемых объектов конструктор без аргументов для первого несериализуемый супертип запущен. Для сериализуемых классов поля инициализируются значением по умолчанию, соответствующим его типу. Затем поля каждого класса восстанавливаются путем вызова конкретного класса методы readObject или, если они не определены, путем вызова метод defaultReadObject. Обратите внимание, что инициализаторы полей и конструкторы не выполняются для сериализуемых классов во время десериализации.

Однако это означает, что если мы поместим в класс статическую переменную (например, переменную-счетчик), она не будет обновляться, как обычно:

class Foo {
    static int t;

    public Foo() {
        t++;
    }
}

public class Bar extends Foo implements Serializable {
    static int t;

    public Bar() {
        t++;
    }
}

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

Интересно, почему десериализация не вызывает конструктор? Поскольку кажется, что это немного прибавит в скорости, это может вызвать потенциальные проблемы. Компилятор может быть легко спроектирован для создания «статического конструктора», который обновляет только статические переменные, которые будут обновлены, и не полагается на внешнюю информацию при загрузке класса.

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

Спасибо за любые вклады заранее!

Ответы [ 2 ]

34 голосов
/ 22 августа 2011

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

11 голосов
/ 22 августа 2011

Не вдаваясь в философию, почему конструктор не вызывается (например, объекты без конструкторов по умолчанию должны быть Serializable), стандартный способ обхода проблем с поведением по умолчанию - предоставить собственный readObject () или writeObject() реализации для вашего класса.

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
    in.defaultReadObject();
    t++;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...