在Java中,有没有办法从匿名内部类访问调用者作用域的变量?
下面的示例代码可以帮助您理解我的需求:
public Long getNumber(final String type, final String refNumber, final Long year) throws ServiceException {
Long result = null;
try {
Session session = PersistenceHelper.getSession();
session.doWork(new Work() {
public void execute(Connection conn) throws SQLException {
CallableStatement st = conn.prepareCall("{ CALL PACKAGE.procedure(?, ?, ?, ?) }");
st.setString(1, type);
st.setString(2, refNumber);
st.setLong(3, year);
st.registerOutParameter(4, OracleTypes.NUMBER);
st.execute();
result = st.getLong(4) ;
}
});
} catch (Exception e) {
log.error(e);
}
return result;
}
代码在一个DAO服务类中。显然它没有编译,因为它要求result
是final,如果它是--它没有编译,因为我试图修改final变量。我绑定到JDK 5。除了完全删除doWork()
之外,有没有办法从doWork()
中设置结果值?
9条答案
按热度按时间eqqqjvef1#
Java并不知道doWork是同步的,也不知道result所在的堆栈帧是否仍然存在,你需要修改一些不在堆栈中的东西。
我想这个会有用的
然后
在
execute()
中。最后,您需要return result[0];
你可能想创建一个类,因为你不喜欢在这里使用数组的样子,但这是基本的想法。
0tdrvxhp2#
这种情况在Java中经常出现,处理它的最简洁的方法是使用一个简单的值容器类,它与数组方法类型相同,但它更简洁。
js81xvg63#
你需要一个“容器”来保存你的值。但是,你不必创建容器类。你可以使用
java.util.concurrent.atomic
包中的类。它们为一个值提供了一个不可变的 Package 器以及一个set
和一个get
方法。你有AtomicInteger
,AtomicBoolean
,AtomicReference<V> (for your objects)
e.t.c在外部方法中:
在匿名内部类方法中
在后面的外部方法中
这里有一个例子。
ttp71kqs4#
长整型是不可变的。如果使用可变类并保存长整型值,则可以更改该值。例如:
hs1rzwqc5#
如果包含类是MyClass --〉
不记得这是否适用于私有变量(我认为它适用)。
只适用于类的属性(类变量)。不适用于方法局部变量。在JSE 7中可能会有闭包来做这类事情。
ghhaqwfi6#
匿名类/方法不是闭包--这正是区别所在。
问题是
doWork()
可能会创建一个新线程来调用execute()
,而getNumber()
可能会在结果设置之前返回--问题甚至更严重:当包含变量的堆栈帧消失时,execute()
应该把结果写在哪里?使用闭包的语言必须引入一种机制,使这些变量在其原始作用域之外保持活动(或者确保闭包不在单独的线程中执行)。解决方法:
0tdrvxhp7#
这个问题的标准解决方案是返回一个值,例如,参见ye olde
java.security.AccessController.doPrivileged
。所以代码看起来像这样:
(Also修复了潜在的资源泄漏,并为任何错误返回
null
。)更新:很明显
Work
来自第三方库,不能修改。所以我建议不要使用它,至少隔离你的应用程序,这样你就不会直接使用它。gz5pxeao8#
从Hibernate 4开始,方法
Session#doReturningWork(ReturningWork<T> work)
将从内部方法返回return瓦尔:(使用Java 8 lambda进行了清理)
svgewumm9#
使用AtomicLong帮助我在一个非常相似的情况下,代码看起来干净。