JAVA 中 flush() 和 reset() 之间的区别

Difference Between flush() vs reset() in JAVA

我只是想知道刷新和重置之间的区别是什么? 为什么在 example 刷新后使用重置?为什么用flush方法擦内存缓存要用reset方法?

ObjectOutputStream oos = new ObjectOutputStream(bos);

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

    object.x++;
}

The reset() will disregard the state of any objects already written to the stream. The state is reset to be the same as a new ObjectOutputStream. The current point in the stream is marked as reset so the corresponding ObjectInputStream will be reset at the same point. Objects previously written to the stream will not be refered to as already being in the stream. They will be written to the stream again.

The flush() method flushes the stream. This will write any buffered output bytes and flush through to the underlying stream.

flush() 方法将清除缓冲区并写入流,而 reset() 将用于更改已写入流的对象。

reset()将使所有已发送的对象失效。如果您再次发送未更改的对象,则只传输一个引用,允许重用已传输对象的缓存版本。这比总是发送整个对象要高效得多。

在您的示例中,对象的成员 x 的值增加了,因此对象发生了变化。如果您需要发送更改后的值,则需要先调用 reset(),以便将对象实际重写到流中。

另一方面,flush() 只会确保数据实际写入流中。写操作只会将数据放入缓冲区,并可能根据缓冲区大小将其写入流。调用 flush() 将保证数据写入流。但是刷新将不会清除缓存的对象。

Why is reset method used if memory cache is wiped by flush method?

flush() 将在底层 OutputStream 中写入 ObjectOutputStream 对象的缓冲区,但不会重置 ObjectOutputStream 对象的整个状态。

如果你打开ObjectOutputStream源代码class,你可以看到在缓冲区之外它包含许多实例字段。
这是一个小片段:

/** 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() 将对此状态产生影响:

Reset will disregard the state of any objects already written to the stream.

Objects previously written to the stream will not be referred to as already being in the stream. They will be written to the stream again.

这些细节很重要,因为 ObjectOutputStream 使用参考共享机制。
所以在流中多次写入相同的对象但具有不同的状态将多次写入具有原始状态的对象。
The top level documentation of ObjectOutputStream 解释了这一点以及更多(重点是我的):

The default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields. References to other objects (except in transient or static fields) cause those objects to be written also. Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written.

你现在应该明白reset()的意思了。


说明缓存问题的示例 ObjectOutputStream:

执行此 class 写入 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 + "]";
    }

}

当您阅读 BOS 的内容时,您将获得:

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

Foo [value=0]

取消注释 reset(),您应该会看到更改:

Foo [value=0]

Foo [value=1]

Foo [value=2]

Foo [value=3]

Foo [value=4]

Foo [value=5]

Foo [value=6]

Foo [value=7]

Foo [value=8]

Foo [value=9]