Sim*_*son 7 java inheritance printstream
令我惊讶的是,下面的代码打印出两次"关闭".通过调试器,它似乎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吗?
mat*_*t b 11
如果您在调试器中查看代码并在close()
方法中设置断点,它将显示谁正在调用您的close()
方法的堆栈跟踪:
后者的完整堆栈跟踪看起来像:
PrintTest$MyPrintStream.close() line: 20
sun.nio.cs.StreamEncoder$CharsetSE.implClose() line: 431 [local variables unavailable]
sun.nio.cs.StreamEncoder$CharsetSE(sun.nio.cs.StreamEncoder).close() line: 160 [local variables unavailable]
java.io.OutputStreamWriter.close() line: 222 [local variables unavailable]
java.io.BufferedWriter.close() line: 250 [local variables unavailable]
PrintTest$MyPrintStream(java.io.PrintStream).close() line: 307
PrintTest$MyPrintStream.close() line: 20
PrintTest.main(java.lang.String[]) line: 27
Run Code Online (Sandbox Code Playgroud)
可悲的是,虽然我不知道为什么 StreamEncoder会回调到你的PrintStream,因为我的IDE没有sun.nio.cs.StreamEncoder的源附件:(这是JDK 6顺便说一句,如果这很重要.
顺便说一句,如果你问这个问题,因为你发现方法中的自定义代码close()
运行了两次,你应该检查是否this.closing
.PrintStream.close()
将此设置为true(以及类的注释状态/* To avoid recursive closing */
).
看一下PrintStream的源码。
它有两个对底层 WritertextOut
和的引用charOut
,一个基于字符,一个基于文本(无论这意味着什么)。此外,它还继承了对基于字节的 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;
Run Code Online (Sandbox Code Playgroud)
在close()
方法中它关闭了所有这些(textOut
与基本相同charOut
)。
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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,有趣的部分是 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));
}
Run Code Online (Sandbox Code Playgroud)
因此,对close()
will call的调用charOut.close()
,又会再次调用原始函数close()
,这就是为什么我们有结束标志来缩短无限递归。