我必须将java.sql.Connection
对象传递给匿名内部类,这意味着我必须引用它final
。但是,我担心任何资源泄漏。
public static String foo(final Connection conn){
...
@Override
public String call() {
...
return runner.query(connection, sql, scalarHandler);
}
}
我无法理解final
关键字的内部运作方式。它如何实际密封对象,使其无法更改为引用另一个对象?将Connection
对象声明为final
是否安全?
答案 0 :(得分:2)
制作一些final
并不会影响它的泄漏倾向 - 也许你会把它与static
混淆,这可能(有时)。
声明一些final
只意味着一旦设置它就不会改变 - 事实上,如果你包含可以改变它的代码,编译器会认为它是一个错误。
标记参数和变量final
以便可以从内部/匿名类访问它们只是获取匿名类的一些奇怪需求的技巧。实际上有一种说法是自动将参数视为final
,如果它们在初始化后从未改变过,只是为了避免在这种情况下标记它们。
答案 1 :(得分:2)
它如何实际密封对象,使其无法更改为引用另一个对象?
小心 - final
是对象的引用的修饰符。所以final
“封印”引用,而不是对象。
这种“密封”有两种方法。一种是通过编译器检查所有final
变量和字段。来自Java语言规范:
如果分配了最终变量,那么这是一个编译时错误,除非它在分配之前肯定是未分配的。
空白的最终类变量必须由静态初始化器明确赋值 声明它的类,或发生编译时错误。
必须在声明它的类的每个构造函数的末尾明确赋值空白的最终实例变量,否则会发生编译时错误。
另一种方法是通过JVM在类加载时完成字节码验证。如果正在操作的字段为putfield
且字节码指令未在特定位置发生,则putstatic
和IllegalAccessError
字节码指令会抛出final
。
但是,你必须要小心一点 - final
关键字只会“粘贴”到字段。临时变量和参数在编译时会丢失final
- 因此,如果您使用不兼容的编译器或使用字节码操作,JVM只能验证final
- 字段。
将
Connection
对象声明为final是否安全?
我不完全确定“安全”是什么意思,但是如果你说“不会导致你的程序出错”,是的,大多数情况下(存在多线程和/或编译 - 时间常数可能会也可能不会改变这个答案)。如果您将final
放在引用上并且您的程序已编译,那么您的程序应该完全按照它的工作方式工作。
答案 2 :(得分:1)
安全吗?这取决于在声明最终后对连接的处理方式。
我必须将java.sql.Connection对象传递给匿名内部 类
这样做可能会产生无法预料的后果。如果您的匿名内部类是回调处理程序,那么在执行回调时,Connection可能已经关闭。
在以下示例中,updateFooTable(...)可能会抛出异常,因为Connection很可能已关闭。
public void test() {
Connection conn = null;
try {
conn = DBUtils.createConnection(dataSource);
foo(conn);
} finally {
DBUtils.close(conn);
}
}
public void foo(final Connection conn) {
MessageBox messageBox = getMessageBox("You want to update Foo?");
messageBox.setCallBackHandler(new MessageCallback() {
@Override
public void yesClicked() {
try {
updateFooTable(conn); //conn could be closed
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
});
messageBox.display();
}