#java #serialization
#java #сериализация
Вопрос:
Что особенного в добавлении конструктора без параметров к несериализуемому, расширяемому классу.
В Effective java автор рассказывает об этой теме.
Наивное добавление конструктора без параметров и отдельного метода инициализации к классу, остальные конструкторы которого устанавливают его инварианты, усложнило бы пространство состояний, увеличивая вероятность ошибки.
Следующий код скопирован из действующей версии Java 2nd[Страница 292-293]
public class AbstractFoo {
private int x, y; // Our state
// This enum and field are used to track initialization
private enum State {
NEW, INITIALIZING, INITIALIZED
};
private final AtomicReference<State> init = new AtomicReference<State>(
State.NEW);
public AbstractFoo(int x, int y) {
initialize(x, y);
}
// This constructor and the following method allow
// subclass's readObject method to initialize our state.
protected AbstractFoo() {
}
protected final void initialize(int x, int y) {
if (!init.compareAndSet(State.NEW, State.INITIALIZING))
throw new IllegalStateException("Already initialized");
this.x = x;
this.y = y;
// ... // Do anything else the original constructor did
init.set(State.INITIALIZED);
}
// These methods provide access to internal state so it can
// be manually serialized by subclass's writeObject method.
protected final int getX() {
checkInit();
return x;
}
protected final int getY() {
checkInit();
return y;
}
// Must call from all public and protected instance methods
private void checkInit() {
if (init.get() != State.INITIALIZED)
throw new IllegalStateException("Uninitialized");
}
// ... // Remainder omitted
}
Все общедоступные и защищенные методы экземпляра в AbstractFoo должны вызывать
Проверьте его, прежде чем делать что-либо еще. Это гарантирует, что вызовы методов завершатся неудачей
быстро и чисто, если плохо написанному подклассу не удается инициализировать экземпляр. Примечание
что инициализированное поле является атомарной ссылкой (java.util.concurrent.
атомарный.Атомарная ссылка). Это необходимо для обеспечения целостности объекта в
лицо решительного противника. В отсутствие этой меры предосторожности, если один поток
должны были вызвать initialize в экземпляре, в то время как второй поток пытался использовать
при этом второй поток может увидеть экземпляр в несогласованном состоянии.
Зачем мы это делаем? Я не до конца понял это. Кто-нибудь может объяснить?
Ответ №1:
У меня была такая же проблема при чтении книги. Я был немного сбит с толку именно в этом месте. Проведя небольшое исследование, я выяснил это.
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
Читать это. Согласно этому «Во время десериализации поля несериализуемых классов будут инициализированы с использованием общедоступного или защищенного конструктора класса без аргументов. Конструктор без аргументов должен быть доступен для сериализуемого подкласса. Поля сериализуемых подклассов будут восстановлены из потока»
Я думаю, это отвечает на ваш вопрос. Надеюсь, это было бы полезно. Если в этом комментарии что-то не так, пожалуйста, не стесняйтесь это исправить.
Ответ №2:
Отдельный метод инициализации очень полезен, когда у вас проблема с многопоточностью. Вы можете посмотреть хорошую статью : http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html