我一直在使用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();
}
}
}
以上是";基本的">尝试使用资源,其中原始代码中没有catch
或finally
块。当您确实有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()");
}
}
}