Философия Java3
Шрифт:
Следующий пример показывает, что надо сделать для полноты операций сохранения и восстановления объекта Externalizable:
// io/Blip3 java
// Восстановление объекта Externalizable import java io *,
import static net.mindview util.Print *;
public class Blip3 implements Externalizable { private int i.
private String s; // Без инициализации public Blip3 {
print("Конструктор Blip3"). // s, i не инициализируются
}
public Blip3(String x. int a) {
print("Blip3(String x, int a)"), s = x, i = a.
// s и i инициализируются
public String toStringO { return s + i; } public void writeExternal(ObjectOutput out) throws IOException {
print("Blip3.writeExternal"); // Необходимо действовать так: out.writeObject(s); out.writelntCi);
}
public void readExternal(Objectlnput in) throws IOException, ClassNotFoundException { pri nt("B1i p3.readExternal"); // Необходимо действовать так: s = (String)in.readObjectO; i = in.readlntO:
}
public static void main(String[] args) throws IOException, ClassNotFoundException { print("Создание объектов:"): Blip3 ЬЗ = new Blip3("Строка ", 47);
print(b3);
ObjectOutputStream о = new ObjectOutputStream(
new File0utputStream("Blip3 out")); print("Сохранение объекта:"); o.write0bject(b3); о.closeO: // Now get it back:
ObjectInputStream in = new ObjectInputStream(
new Fi1eInputStream("B1ip3.out")); print("Восстановление ЬЗ:"); ЬЗ = (Blip3)in. readObjectO; print(b3);
}
} /* Output: Создание объектов: Blip3(String x, int a) Строка 47
Сохранение объекта: Blip3.writeExternal Восстановление ЬЗ: Конструктор Blip3 B1i рЗ.readExternal Строка 47 *///:-
Поля s и i инициализируются только во втором конструкторе, но не в конструкторе по умолчанию. Это значит, что, если переменные s и i не будут инициализированы в методе readExternal, s останется ссылкой null, a i будет равно нулю (так как при создании объекта его память обнуляется). Если вы закомментируете две строки после фраз Необходимо действовать так и запустите программу, то обнаружите, что так оно и будет: в восстановленном объекте ссылка s имеет значение null, а целое i равно нулю.
Если вы наследуете от объекта, реализующего интерфейс Externalizable, то при выполнении сериализации следует вызывать методы базового класса writeExternal и readExternal, чтобы правильно сохранить и восстановить свой объект.
Итак, чтобы сериализация выполнялась правильно, нужно не просто записать всю значимую информацию в методе writeExternal (для объектов Externalizable не существует автоматической записи объектов-членов), но и восстановить ее затем в методе readExternal. Хотя сначала можно запутаться и подумать, что из-за вызова конструктора по умолчанию все необходимые действия по записи и восстановлению объектов Externalizable происходят сами по себе. Но это не так.
Ключевое слово transient
При управлении процессом сериализации может возникнуть ситуация, при которой автоматическое сохранение и восстановление некоторого подобъекта нежелательно — например, если в объекте хранится некоторая конфиденциальная информация (пароль и т. д.). Даже если информация в объекте
Первый способ предотвратить сериализацию некоторой важной части объекта — реализовать интерфейс Externalizable, что уже было показано. Тогда автоматически вообще ничего не записывается, и управление отдельными элементами находится в ваших руках (внутри writeExternal).
Однако работать с объектами Serializable удобнее, поскольку сериализация для них проходит полностью автоматически. Чтобы запретить запись некоторых полей объекта Serializable, воспользуйтесь ключевым словом transient. Фактически оно означает: «Это не нужно ни сохранять, ни восстанавливать — это мое дело».
Для примера возьмем объект Login, который содержит информацию о некотором сеансе входа в систему, с вводом пароля и имени пользователя. Предположим, что после проверки информации ее необходимо сохранить, выборочно, без пароля. Проще всего удовлетворить заявленным требованиям, реализуя интерфейс Serializable и объявляя поле с паролем password как transient. Вот как это будет выглядеть:
//• io/Logon java
// Ключевое слово "transient"
import java util concurrent *.
import java.io.*;
import java util *.
import static net mindview util Print.*,
public class Logon implements Serializable { private Date date = new DateO. private String username; private transient String password: public Logon(String name, String pwd) { username = name, password = pwd.
}
public String toStringO {
return "информация о сеансе. \n пользователь. " + username +
"\п дата " + date + "\п пароль " + password;
public static void main(String[] args) throws Exception { Logon a = new Logon("Пользователь". "Пароль"), print("Сеанс a = " + a). ObjectOutputStream о = new ObjectOutputStream(
new FileOutputStream("Logon out")), о writeObject(a); о closeO,
TimeUnit.SECONDS.sleep(l). // Задержка // Восстановление-
ObjectlnputStream in = new ObjectInputStream(
new FileInputStream("Logon out")), print ("Восстановление объекта Время: " + new DateO); a = (Logon)in readObjectO, print("Сеанс a = " + a).
}
} /* Output
Сеанс a = информация о сеансе пользователь- Пользователь дата- Sat Nov 19 15-03 26 MST 2005 пароль Пароль
Восстановление объекта. Время: Sat Nov 19 15.03 28 MST 2005
Сеанс а = информация о сеансе пользователь. Пользователь дата Sat Nov 19 15.03 26 MST 2005 пароль, null
*/// ~
Поля date и username не имеют модификатора transient, поэтому сериализация для них проводится автоматически. Однако поле password описано как transient и поэтому не сохраняется на диске; механизм сериализации его также игнорирует. При восстановлении объекта поле password равно null. Заметьте, что при соединении строки (String) со ссылкой null перегруженным оператором + ссылка null автоматически преобразуется в строку null.