Разница между flush () и reset () в JAVA - PullRequest
0 голосов
/ 30 июня 2018

Мне просто интересно, в чем разница между сбросом и сбросом? Почему используется сброс после сброса в примере ? Почему используется метод сброса, если кэш памяти очищается методом очистки?

ObjectOutputStream oos = new ObjectOutputStream(bos);

while(true){
    oos.writeObject(object);
    oos.flush();
    oos.reset();

    object.x++;
}

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

reset() сделает недействительными все отправленные объекты. При повторной отправке неизмененных объектов передается только ссылка, позволяющая повторно использовать кэшированную версию уже переданного объекта. Это гораздо эффективнее, чем всегда отправлять весь объект.

В вашем примере значение элемента x объекта увеличивается, поэтому объект изменяется. Если вам нужно отправить измененные значения, сначала необходимо вызвать reset(), чтобы объект был фактически переписан в поток.

С другой стороны, flush() будет только следить за тем, чтобы данные действительно записывались в поток. Операция записи только помещает данные в буфер и может записывать их в поток в зависимости от размера буфера. Вызов flush() гарантирует, что данные будут записаны в поток. Но flush не очистит кэшированные объекты.

0 голосов
/ 30 июня 2018

Почему используется метод сброса, если кэш памяти очищается методом очистки?

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]

0 голосов
/ 30 июня 2018

Функция reset () игнорирует состояние любых объектов, уже записанных в поток. Состояние сбрасывается, чтобы быть таким же, как новый ObjectOutputStream. Текущая точка в потоке помечена как сброшенная, поэтому соответствующий ObjectInputStream будет сброшен в той же точке. Объекты, ранее записанные в поток, не будут рассматриваться как уже в потоке. Они будут снова записаны в поток.

Метод flush () очищает поток. Это напишет любой буфер вывод байтов и очистка до нижележащего потока.

Метод flush() будет очищать буфер и записывать в поток, тогда как reset() будет использоваться для изменения объектов, уже записанных в поток.

...