问题描述
我一直在使用 try-with-resources 语句。
try(FileReader rd = new FileReader("Test.txt");){}
catch (Exception e) {e.printstacktrace();}
对资源使用 try 的好处主要是避免指定 finally 块来关闭资源。
这就是我的研究过程开始的地方。
经过调试,我发现 FileReader 扩展了 InputStreamReader。里面 FileReader 类此构造函数调用
public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
}
创建 FileInputStream 类的对象。 FileInputStream 扩展了实现 Closeable 接口的 InputStream。
在 FileInputStream 类内部调用 close 方法,如下所示,并使用本机方法执行关闭资源所需的操作。
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();
}
});
}
现在当我使用一些自定义类实现 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 实例/对象是如何创建的吗?
提前致谢。
解决方法
背景
在解决您的实际问题之前,了解try-with-resources 的工作原理很重要。为此,我们可以查看 §14.20.3 of the Java Language Specification (JLS)。基本上,该章节告诉您的是,如果您有以下代码:
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();
}
}
}
以上是“基本”try-with-resources 的翻译,其中原始代码中没有 catch
或 finally
块。当您确实有 catch
和/或 finally
块(即“扩展的”try-with-resources)时:
try (AutoCloseable closeable = ...) {
// try something
} catch (Exception ex) {
// handle error
} finally {
// finally...
}
然后它简单地将我们之前的内容包装在另一个 try-catch-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()");
}
}
}