为什么 PrintStream.close() 最终被调用两次?
令我惊讶的是,以下代码打印出“Close”两次。 通过调试器运行,似乎 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 吗?
Somewhat to my surprise, the following code prints out "Close" twice. Running through the debugger, it seems MyPrintStream.close()
calls super.close()
, which ends up calling MyPrintStream.close()
again.
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();
}
}
Why is this happening? Should I not be extending PrintStream?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您在调试器中查看代码并在
close()
方法中设置断点,它将显示谁正在调用您的close( )
方法:后者的完整堆栈跟踪如下所示:
遗憾的是,我无法告诉 为什么 StreamEncoder会回调到您的 PrintStream 中,因为我的 IDE 没有 sun.nio.cs.StreamEncoder 的源附件:( 顺便说一句,如果这很重要,这是 JDK 6。
顺便说一句,如果您问这个问题是因为您注意到
close()
方法中的自定义代码运行了两次,您确实应该检查this.writing
是否。 close() 将其设置为 true (并且类的注释状态/* 以避免递归关闭 */
)。If you look at your code in a debugger and set a breakpoint in the
close()
method, it'll reveal the stacktraces of who is calling yourclose()
method:the complete stacktrace for the latter looks like:
Sadly though I can't tell why StreamEncoder would call back into your PrintStream though, as my IDE doesn't have a source attachment for sun.nio.cs.StreamEncoder :( This is JDK 6 btw, if that matters.
By the way, if you are asking this question because you noticed that custom code in your
close()
method is running twice, you should really be checking ifthis.closing
.PrintStream.close()
sets this to true (and the class's comments state/* To avoid recursive closing */
).看一下PrintStream的源码。
它有两个对底层 Writer
textOut
和charOut
的引用,一个基于字符,一个基于文本(无论这意味着什么)。 此外,它还继承了对基于字节的 OutputStream 的第三个引用,称为out
。在
close()
方法中,它关闭所有这些(textOut
与charOut
基本相同)。现在,有趣的部分是 charOut 包含一个对 PrintStream 本身的引用(包装)(注意构造函数中的 init(new OutputStreamWriter(this)) ),
因此,调用 close( ) 将调用
charOut.close()
,后者又调用原来的close()
,这就是为什么我们有关闭标志来缩短无限递归。Take a look at PrintStream's source.
It has two references to the underlying Writer
textOut
andcharOut
, one character-base, and one text-based (whatever that means). Also, it inherits a third reference to the byte-based OutputStream, calledout
.In the
close()
method it closes all of them (textOut
is basically the same ascharOut
).Now, the interesting part is that charOut contains a (wrapped) referenced to the PrintStream itself (note the
init(new OutputStreamWriter(this))
in the constructor )So, the call to
close()
will callcharOut.close()
, which in turn calls the originalclose()
again, which is why we have the closing flag to cut short the infinite recursion.