JAVAutil。扫描器关闭构造函数链接期间生成的Java扫描器对象
我正在使用构造函数链接,我担心它会导致资源泄漏。以下是我的两个构造函数:
/**
* Constructor to build the map based off of a file. Redirects to the Scanner-based constructor
* @param fileName the name of the file to open
*/
public GeoMap(String fileName) throws FileNotFoundException {
this(new Scanner(new File(fileName)));
}
/**
* Constructor to build the map based off of a Scanner. (Probably from an open file.)
* @param scanner the Scanner to read
*/
public GeoMap(Scanner scanner) {
// goes on to read the string data and make an object...
从任何类型的Scanner
(键盘、文件等)创建对象都很重要,尽管它通常是从文件创建的。问题是,我认为这里正在发生资源泄漏。每当我阅读一个文件时,我喜欢在完成后关闭它。问题是,构造函数链接意味着this()
调用必须是第一行。我倾向于这样做:
this(Scanner scannerToClose = new Scanner(new File(fileName)));
在我看来,这会给我一个Scanner
的名字,然后我就可以结束了。但这似乎真的让编译器感到困惑——我从中得到了大约5个编译时错误,包括许多“找不到符号”的问题,这意味着编译器不适合这种类型的东西。Java支持这个吗?或者我需要创建两个构造函数调用的完全不同的initFromScanner()
函数吗?(不优雅。)
谢谢
# 1 楼答案
我假设您的问题是,如果您在构造函数中创建了相关的扫描仪,并且该扫描仪采用
fileName
,那么您只想关闭它。我认为您的想法没有任何问题,即使用两个构造函数都调用的init
方法。我不认为那是不雅的我想我要做的是创建第三个私有构造函数,而不是
init
方法。这两种方法实际上都是一样的,尽管可能在某个时候,您希望能够传入一个预构建的扫描程序,您希望在构造函数调用结束时关闭该扫描程序,在这种情况下,您可以将此新构造函数公开,以便从外部调用它在这两种情况下,我要做的是向新的构造函数/方法传递一个布尔“closeScanner”参数,该参数指示是否应该关闭扫描仪。以下是我在代码方面的想法:
# 2 楼答案
让我们从以下内容开始:
这里有资源泄漏吗?嗯,这取决于关闭
Scanner
的责任在哪里如果责任在于建造商,那么我们可以像这样堵住漏洞:
这是理想的解决方案,但它假定
Scanner
的作用寿命是构造函数如果这是呼叫者的责任,那么呼叫者需要处理泄漏预防。这是可行的。。。但超出了这个问题的范围
如果这既不是构造函数的责任,也不是调用方的责任,那么您需要将
GeoMap
本身视为一种资源,以及所有需要的资源首先,是否存在潜在的资源泄漏
理论上,是的。
Scanner
构造函数可以打开文件的流,然后失败,使流保持打开状态实际上,这是极不可能的。如果我们忽略类库中的错误,以及应用程序错误,比如使用无法识别的字符集名称,那么
new Scanner
的自发故障可能会泄漏文件描述符等的唯一原因就是您得到了OOME。但无论如何,这可能会触发一个完整的GC那之后呢
答案取决于前面关于
GeoMap(Scanner)
构造函数的职责所在的答案如果责任在于该建造商,我们知道如何避免泄漏;见上文
否则。。。我们有一个问题:
Scanner
的使用方式李>总之,根据您指定和实现
GeoMap(Scanner)
的方式,GeoMap(String)
构造函数可以实现为实际的防漏# 3 楼答案
首先,类
GeoMap
应该定义它如何处理构造函数中提供给它的扫描器;通常,当允许它创建自己的Scanner
实例(如示例中所示)时,策略是GeoMap
实例可以使用该扫描仪执行任何操作,包括关闭它–这意味着它拥有它,并且所有权在相应的构造函数中转移如果不是这种情况(它不拥有扫描器),则必须删除
GeoMap(String)
构造函数(因为,当GeoMap
实例不拥有它时,还有谁会拥有它并在以后处理它呢?),或者,您必须采用与以下类似的设计:这里,所有权由标志
m_MayCloseScanner
跟踪。 不幸的是,这还不能解决您的资源泄漏问题:当不再使用GeoMap
实例时,扫描器仍然不会关闭当你的
GeoMap
实例根本不拥有扫描器时,你不在乎,扫描器占用的资源是一个废物(aproblemofotherppeople)好的,当您将只需要扫描器来初始化
GeoMap
实例时,您可以使用一个init()
方法在完成后关闭扫描器:当然,当
GeoMap
可能拥有或不拥有扫描仪时,结束行需要如下所示:if( m_MayCloseScanner ) m_Scanner.close;
但是如果init选项不起作用,那么
GeoMap
实例需要一个析构函数。Java中不存在析构函数的概念,最接近它的是实现finalize()
,但这一概念在一段时间前就被弃用了(最后是Java 9),理由很充分看看this post如何为
GeoMap
类使用Cleaner
、PhantomReference
和Closeable
。一开始看起来有点混乱,但最后显示出相对直截了当# 4 楼答案
呼叫扫描仪。在GeoMap(扫描仪)构造函数的末尾关闭()强>
这将关闭在GeoMap(字符串文件名)中创建的扫描仪,因为对它的引用作为扫描仪传递到GeoMap(扫描仪)中
实际上,scanner变量指向创建的新扫描仪,因此调用scanner。close()在任何方法中的任何位置,对它可能在范围内的任何和所有其他方法关闭它
下面是一个演示扫描仪面向对象特性的程序:
输入。txt:
Smitty
输出:
本质上,扫描仪创建在哪里并不重要,如果它在任何一点关闭,它在范围内的任何地方都会关闭