Для примера возьмем объект 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.
Также видно, что поле date сохраняется на диске и при восстановлении его значение не меняется.
Так как объекты Externalizable по умолчанию не сохраняют полей, ключевое слово transient для них не имеет смысла. Оно применяется только для объектов Serializable.
Альтернатива для Externalizable
Если вас по каким-либо причинам не прельщает реализация интерфейса Externalizable, существует и другой подход. Вы можете реализовать интерфейс Serializable и
Эти методы должны иметь жестко фиксированную сигнатуру:
private void writeObject(ObjectOutputStream stream)
throws IOException;
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
С точки зрения проектирования программы этот подход вообще непонятен. Во-первых, можно подумать, что, раз уж эти методы не являются частью базового класса и не определены в интерфейсе Serializable, у них должен быть свой собственный интерфейс. Но так как методы объявлены закрытыми (private), вызываться они могут лишь членами их собственного класса. Однако члены обычных классов их не вызывают, вместо этого вызов исходит из методов writeObject() и readObject() классов ObjectlnputStream и ObjectOutputStream. (Я не стану разражаться долгой тирадой о выборе тех же имен методов, а скажу лишь одно слово: неразумно.) Интересно, каким образом классы ObjectlnputStream и ObjectOutputStream обращаются к закрытым членам другого класса? Можно лишь предположить, что это относится к таинству сериализации.
Так или иначе, все методы, описанные в интерфейсе, реализуются как открытые (public), поэтому, если методы writeObject() и readObject() должны быть закрытыми (private), они не могут быть частью какого-либо интерфейса. Однако вам необходимо строго следовать указанной нотации, и результат очень похож на реализацию интерфейса.
Судя по всему, при вызове метода ObjectOutputStream.writeObject() передаваемый ему объект Serializable тщательно анализируется (вне всяких сомнений, с использованием механизма рефлексии) в поисках его собственного метода writeObject(). Если такой метод существует, процесс стандартной сериализации пропускается, и вызывается метод объекта writeObject(). Аналогичные действия происходят и при восстановлении объекта.
Существует и еще одна хитрость. В вашем собственном методе writeObject() можно вызвать используемый в обычной сериализации метод writeObject(), для этого вызывается метод defaultWriteObject(). Аналогично, в методе readObject() можно вызвать метод стандартного восстановления defaultReadObject(). Следующий пример показывает, как производится пользовательское управление хранением и восстановлением объектов Serializable:
//: io/SerialCtl java