Ответ 1
Deserialization не вызывает конструктор, потому что целью этого является выражение состояния объекта по мере его сериализации, запуск кода конструктора может помешать ему.
Java-сериализация для Java 1.5:
Для сериализуемых объектов конструктор no-arg для первого запускается несериализуемый супертип. Для сериализуемых классов поля инициализируются значением по умолчанию, соответствующим его типу. Затем поля каждого класса восстанавливаются вызовом класса 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
- один за другим.
Интересно, почему десериализация не вызывает конструктор? Поскольку кажется, что, хотя это немного улучшится, это может вызвать потенциальные проблемы. Компилятор может быть легко разработан для создания "статического конструктора", который обновляет только статические переменные, которые будут обновляться, и не будет полагаться на внешнюю информацию при загрузке класса.
Кроме того, интересно, какой лучший способ избежать этого? Решение, о котором я могу думать, заключается в упаковке десериализации с помощью операции по статической переменной.
Спасибо за любые вводы заранее!
Deserialization не вызывает конструктор, потому что целью этого является выражение состояния объекта по мере его сериализации, запуск кода конструктора может помешать ему.
Не вдаваясь в философию того, почему конструктор не вызывается (объекты без конструкторов по умолчанию, например, должны быть Serializable), стандартный способ работы с проблемами с поведением по умолчанию состоит в том, чтобы предоставить свой собственный readObject() или writeObject() для вашего класса.
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
in.defaultReadObject();
t++;
}