当某个自定义类在使用try with resources时实现Closeable接口时,FileInputStream实



我一直在使用try-with-resources语句。

try(FileReader rd = new FileReader("Test.txt");){} 
catch (Exception e) {e.printStackTrace();}

使用try-with-resources的好处主要是避免指定finally块来关闭资源。

这就是我的研究过程开始的地方。

经过一些调试,我发现FileReader扩展InputStreamReader。在…内这个构造函数称之为的FileReader类

public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}

其创建FileInputStream类的对象FileInputStream扩展了InputStream,实现了Closeable接口

在FileInputStream类内部,关闭方法被调用如下,并使用本机方法执行关闭资源所需的操作。

public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}

所以我理解了close方法就是这样被调用的。

现在,当我用一些自定义类实现Closeable接口时,我无法理解的是直接如

public class MyClass implements Closeable 
{
public void close() 
{
System.out.println("connection closed...");
}
}

并像这样使用

try(MyClass rd = new MyClass();)
{} 
catch (Exception e) 
{e.printStackTrace();}

它仍在自动调用自定义类MyClass中的close方法,而无需我显式调用它。当我运行调试时,它将进入FileInputStream类,该类扩展了实现Closeable接口的InputStream类。最后,这种方法被称为

public void close() throws IOException {
synchronized (closeLock) {
if (closed) {
return;
}
closed = true;
}
if (channel != null) {
channel.close();
}
fd.closeAll(new Closeable() {
public void close() throws IOException {
close0();
}
});
}

有人能向我解释一下FileInputStream实例/对象是如何创建的吗?

提前谢谢。

背景

在解决您的实际问题之前,了解如何尝试资源是很重要的。为此,我们可以查看Java语言规范(JLS(的§14.20.3。从本质上讲,这一章告诉你的是,如果你有以下代码:

try (AutoCloseable closeable = ...) {
// try something
}

注意:try-with-resources语句适用于任何java.lang.AutoCloseable实现。java.io.Closeable接口扩展了java.lang.AutoCloseable界面

然后编译器会把它翻译成你写的东西:

AutoCloseable closeable = ...;
Throwable primary = null;
try {
// try something
} catch (Throwable t) {
primary = t;
throw t;
} finally {
if (closeable != null) {
if (primary != null) {
try {
closeable.close();
catch (Throwable suppressed) {
primary.addSuppressed(suppressed);
}
} else {
closeable.close();
}
}
}

以上是";基本的">尝试使用资源,其中原始代码中没有catchfinally块。当您确实有catch和/或finally块(即"扩展的">尝试使用资源(时,如下所示:

try (AutoCloseable closeable = ...) {
// try something
} catch (Exception ex) {
// handle error
} finally {
// finally...
}

然后它简单地将我们之前的内容包装在另一个尝试捕获最终块中:

try {
// "basic" translation
} catch (Exception ex) {
// handle error
} finally {
// finally...
}

正如你所看到的,这里没有什么特别的事情发生。一切都相当简单明了。


您的问题

回答您的问题:FileInputStream不是作为try-with-resources语句的一部分隐式创建的。考虑到您的MyClass实现,您声称在调试代码时所看到的是不可能的。您必须调试另一段代码,或者源代码与编译的代码不同步。我猜是前者。如果您要调试以下内容:

import java.io.Closeable;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try (MyClass foo = new MyClass()) {
// try something...
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class MyClass implements Closeable {

@Override
public void close() throws IOException {
System.out.println("MyClass#close()");
}
}
}

您不会看到FileInputStream#close()被调用——无论如何也不会被该代码调用。为此,我们可以根据JLS的§14.20.3翻译上述代码,该代码给出:

import java.io.Closeable;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
MyClass foo = new MyClass();
Throwable primary = null;
try {
try {
// try something...
} catch (Throwable t) {
primary = t;
throw t;
} finally {
if (foo != null) {
if (primary != null) {
try {
foo.close();
} catch (Throwable suppressed) {
primary.addSuppressed(suppressed);
}
} else {
foo.close();
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static class MyClass implements Closeable {
@Override
public void close() throws IOException {
System.out.println("MyClass#close()");
}
}
}