是否可以懒惰地实例化最终字段?
以下代码无法编译:
public class Test{
private final Connection conn;
public Connection getConnection(){
if(conn==null){
conn = new Connection();
}
return conn;
}
}
有替代方案吗?
答案 0 :(得分:8)
没有。最终字段的要点是它在构造期间设置一次,之后永远不会改变。在您的情况下,编译器或VM如何知道有关conn
的任何有用信息?怎么会知道只有那个属性应该能够设置它,而不是其他方法呢?
也许如果你解释了你想要的语义,我们可以想出一个替代品。您可能有一个“提供者”接口,表示获取值的方法,然后是MemoizingProvider
代理另一个提供者,但只有一次,否则缓存该值。这也不能为缓存值设置最终字段,但至少它只能在一个地方。
答案 1 :(得分:3)
这是使用Memoisation(使用Callables)的一种方法:
班级备忘录:
public class Memo<T> {
private T result;
private final Callable<T> callable;
private boolean established;
public Memo(final Callable<T> callable) {
this.callable = callable;
}
public T get() {
if (!established) {
try {
result = callable.call();
established = true;
}
catch (Exception e) {
throw new RuntimeException("Failed to get value of memo", e);
}
}
return result;
}
}
现在我们可以创建一个最终的conn!
private final Memo<Connection> conn = new Memo<Connection>(
new Callable<Connection>() {
public Connection call() throws Exception {
return new Connection();
}
});
public Connection getConnection() {
return conn.get();
}
答案 2 :(得分:1)
dhiller的答案是经典的双重检查锁定错误,不使用。
答案 3 :(得分:0)
正如Jon Skeet所说,不,没有。
解释您的代码示例,您可能希望执行以下操作:
public class Test{
private final Object mutex = new Object(); // No public locking
private Connection conn;
public Connection getConnection(){
if(conn==null){
synchronized (mutex) {
if(conn==null){
conn = new Connection();
}
}
}
return conn;
}
}
答案 4 :(得分:0)
作为旁注,可以更改最终字段。至少是实例字段。你只需要反思一下:
import java.lang.reflect.Field;
public class LazyFinalField {
private final String finalField = null;
public static void main(String[] args) throws Exception {
LazyFinalField o = new LazyFinalField();
System.out.println("Original Value = " + o.finalField);
Field finalField = LazyFinalField.class.getDeclaredField("finalField");
finalField.setAccessible(true);
finalField.set(o, "Hello World");
System.out.println("New Value = " + o.finalField);
}
}
Original Value = null
New Value = Hello World