令我惊讶的是,以下代码两次打印出“关闭”。在调试器中运行,似乎MyPrintStream.close()调用super.close(),最终再次调用MyPrintStream.close()
import java.io.*;public class PrintTest{ static class MyPrintStream extends PrintStream { MyPrintStream(OutputStream os) { super(os); } @Override public void close() { System.out.println("Close"); super.close(); } } public static void main(String[] args) throws IOException { PrintStream ps = new MyPrintStream(new FileOutputStream(File.createTempFile("temp", "file"))); ps.println("Hello"); ps.close(); }}
为什么会这样呢?我不应该扩展PrintStream吗?

最佳答案

看一下PrintStream的来源。

它有两个对基础Writer的textOutcharOut的引用,一个基于字符的引用和一个基于文本的引用(无论如何)。而且,它继承了对基于字节的OutputStream的第三个引用,称为out

/**
 * Track both the text- and character-output streams, so that their buffers
 * can be flushed without flushing the entire stream.
 */
private BufferedWriter textOut;
private OutputStreamWriter charOut;

close()方法中,它将全部关闭(textOutcharOut基本相同)。
 private boolean closing = false; /* To avoid recursive closing */

/**
 * Close the stream.  This is done by flushing the stream and then closing
 * the underlying output stream.
 *
 * @see        java.io.OutputStream#close()
 */
public void close() {
synchronized (this) {
    if (! closing) {
    closing = true;
    try {
        textOut.close();
        out.close();
    }
    catch (IOException x) {
        trouble = true;
    }
    textOut = null;
    charOut = null;
    out = null;
    }
}
}

现在,有趣的部分是charOut包含对PrintStream本身的引用(包装)(请注意构造函数中的init(new OutputStreamWriter(this)))
private void init(OutputStreamWriter osw) {
   this.charOut = osw;
   this.textOut = new BufferedWriter(osw);
}

/**
 * Create a new print stream.
 *
 * @param  out        The output stream to which values and objects will be
 *                    printed
 * @param  autoFlush  A boolean; if true, the output buffer will be flushed
 *                    whenever a byte array is written, one of the
 *                    <code>println</code> methods is invoked, or a newline
 *                    character or byte (<code>'\n'</code>) is written
 *
 * @see java.io.PrintWriter#PrintWriter(java.io.OutputStream, boolean)
 */
public PrintStream(OutputStream out, boolean autoFlush) {
this(autoFlush, out);
init(new OutputStreamWriter(this));
}

因此,对close()的调用将调用charOut.close(),后者又再次调用原始的close(),这就是为什么我们有关闭标志来缩短无限递归的原因。

08-17 00:34
查看更多