JAVA中flush()与reset()的区别

Efe*_*bek 5 java io flush reset

我只是想知道刷新和重置之间有什么区别?为什么在示例中使用刷新后重置?如果使用flush方法擦除内存缓存,为什么还要使用reset方法?

ObjectOutputStream oos = new ObjectOutputStream(bos);

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

    object.x++;
}
Run Code Online (Sandbox Code Playgroud)

dav*_*xxx 6

如果使用flush方法擦除内存缓存,为什么还要使用reset方法?

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;
Run Code Online (Sandbox Code Playgroud)

有些处理转换,其他处理缓存,所以 for... ObjectOutputStream.reset()会对此状态产生影响:

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

将 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 + "]";
    }

}
Run Code Online (Sandbox Code Playgroud)

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

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

富[值=0]

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

富[值=0]

富[值=1]

富[值=2]

富[值=3]

富[值=4]

富[值=5]

富[值=6]

富[值=7]

富[值=8]

富[值=9]