Почему используется метод сброса, если кэш памяти очищается методом очистки?
flush()
запишет буфер объекта ObjectOutputStream
в базовый OutputStream
, но не сбросит все состояние объекта ObjectOutputStream
.
Если вы откроете класс исходного кода ObjectOutputStream
, вы увидите, что за пределами буфера он содержит много полей экземпляра.
Вот небольшой фрагмент:
/** filter stream for handling block data conversion */
private final BlockDataOutputStream bout;
/** obj -> wire handle map */
private final HandleTable handles;
/** obj -> replacement obj map */
private final ReplaceTable subs;
/** recursion depth */
private int depth;
/** buffer for writing primitive field values */
private byte[] primVals;
Некоторые обрабатывают преобразование, другие обрабатывают кеш, и так для ...
ObjectOutputStream.reset()
будет влиять на это состояние:
Сброс не учитывает состояние любых объектов, уже записанных в
поток.
и
Объекты, ранее записанные в поток, не будут называться
уже в потоке. Они будут снова записаны в поток.
Эти детали важны, так как ObjectOutputStream
использует механизм совместного использования ссылок.
Таким образом, запись в поток несколько раз одного и того же объекта, но с другим состоянием, приведет к записи объекта с исходным состоянием несколько раз.
Документация верхнего уровня ObjectOutputStream объясняет это и многое другое (выделение мое):
Механизм сериализации по умолчанию для объекта записывает класс
объект, сигнатура класса и значения всех непереходных
и нестатические поля. Ссылки на другие объекты (кроме
переходные или статические поля) также вызывают запись этих объектов.
Несколько ссылок на один объект кодируются с использованием ссылки
механизм совместного использования, так что графики объектов могут быть восстановлены в
та же форма, что и при написании оригинала .
Теперь вы должны понимать значение reset()
.
Пример, иллюстрирующий проблему с кешем ObjectOutputStream
:
Выполнить этот класс, который пишет 10 раз один и тот же объект, но с другим состоянием, я не ObjectOutputStream
без вызова reset()
между записями:
public class FlushAndReset {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
Foo foo = new Foo();
for (int i = 0; i < 10; i++) {
foo.setValue(i);
oos.writeObject(foo);
oos.flush();
// oos.reset();
}
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
for (int i = 0; i < 10; i++) {
Object obj = ois.readObject();
System.out.println(obj);
}
}
}
С Foo, определенным как:
public class Foo implements Serializable {
private int value;
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Foo [value=" + value + "]";
}
}
Когда вы будете читать содержимое ЛС, вы получите:
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Foo [значение = 0]
Раскомментируйте reset()
, и вы увидите изменение:
Foo [значение = 0]
Foo [значение = 1]
Foo [значение = 2]
Foo [значение = 3]
Foo [значение = 4]
Foo [значение = 5]
Foo [значение = 6]
Foo [значение = 7]
Foo [значение = 8]
Foo [значение = 9]