我有一节课
class Something {
private Map<String, RandomAccessFile> map = new LinkedHashMap<>() {
@Override
protected boolean removeEldestEntry(...) { also closes the file if it returns true; }
@Override
public RandomAccessFile remove(Object filename) { closes the file too; }
};
}
这是文件名到文件句柄的Map。其思想是保持一些文件处于打开状态,以便something类的成员函数可以写入任何打开的文件。
现在我想重写finalize,以便当对象超出范围时,我们关闭所有文件。但是finalize被否决了。因此,我们的想法是调用cleaner.register(map,runnable),其中runnable获取“map”中的所有randomaccessfile并关闭每个文件。i、 例如 cleaner.register(map, () -> map.values().forEach(close file))
. 但是这使得runnable有一个对Map的引用,所以Map永远不会变得不可访问-类linkedhashmap.linkedvalues不是静态类。
有没有办法做到这一点?
1条答案
按热度按时间toe950271#
必须将其可访问性应控制清理的对象与清理所需的数据分开。
对你来说
Something
示例将确定文件是否仍在使用中,而map示例可以在清理操作期间使用,前提是您保持map私有并且从不分发它。还有一些要点需要注意。文件
Cleaner
说:清理操作可以是lambda,但是非常容易通过引用要清理的对象的字段来捕获对象引用,从而防止对象变得不可访问。如上所述,使用静态嵌套类可以避免意外地保留对象引用。
使用lambda表达式时
() -> map.values().forEach(close file))
以及map
是当前Something
示例,您已隐式捕获this
. 但是,即使您修复了cleaner,让它只引用map示例,也有一个问题,即map本身是的一个匿名子类LinkedHashMap
匿名内部类总是有一个对外部示例的隐式引用。您可以通过在静态上下文中执行初始化来修复这两个问题:
通过使用
static
方法,不能有任何隐式引用this
以及instance
参数已故意键入为Object
,使意外访问map类或清理操作中的成员变得更加困难。但请注意
LinkedHashMap
并不能保证所有的删除操作都要经过一次重写remove
方法。此外,更换操作不使用remove
. 它可以为您的内部使用时remove
是唯一的手术put
)那个Something
类使用,但在这种情况下,使文件关闭调用者的职责也可能更干净。也就是说,你根本不应该实施清洁。如果所有的清理工作都在进行,那就是关闭
RandomAccessFile
,这是过时的,因为在RandomAccessFile
不关闭就无法访问。如果依赖那个清洁工感觉不舒服,那你就走对了。但是依靠Something
他的清洁工一点也不好。通常,变量作用域和对象可达性只是远程连接的。看到java能在对象仍在作用域中时完成它吗?或finalize()在Java8中为连接的实际问题调用强可达对象。当然,在java中何时调用finalize()方法中描述的计时问题?也适用于清洁剂。垃圾收集器可能永远不会运行,例如当内存足够时,也可能运行但不收集所有无法访问的对象,例如当它回收了足够的内存以便应用程序继续运行时。
如果要在变量作用域的末尾进行清理,可以使用try with resources语句。你只需要实现
AutoCloseable
或者它的一个子类型,提供close()
方法关闭所有文件。那么你可以很容易地说