2009-03-23 7 views
2

Можно ли лениво создать окончательное поле?Леновый экземпляр конечного поля

Следующий код не компилируется:

public class Test{ 
    private final Connection conn; 

    public Connection getConnection(){ 
     if(conn==null){ 
      conn = new Connection(); 
     } 
     return conn; 
    } 
} 

Есть ли альтернатива?

ответ

3

Вот один из способов вы можете сделать это с помощью мемоизация (с вызываемых объектов):

Класс Memo:

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; 
    } 
} 

Теперь мы можем создать окончательный соед!

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(); 
} 

Source

8

№ Пункт конечного поля состоит в том, что он установлен один раз, во время строительства и никогда не будет меняться после этого. Как компилятор или виртуальная машина знают что-нибудь полезное о conn в вашем случае? Как он узнает, что только это свойство должно иметь возможность установить его, а не какой-либо другой метод?

Возможно, если вы объясните, какова вам семантика, мы можем придумать альтернативу. Возможно, у вас может быть интерфейс «поставщик», представляющий способ получения значения, а затем MemoizingProvider, который проксирует другой поставщик, но только один раз, кэшируя значение в противном случае. Это также не могло бы иметь конечное поле для кэшированного значения, но, по крайней мере, оно было бы только в одном месте.

0

Как сказал Джон Скит, нет, нет.

Устный ваш образец кода вы можете сделать что-то вроде этого:

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; 
    } 
} 
+0

Я думаю, окончательный модификаторов в «подключ» поле опечатка, верно? – Nicolas

+5

Вы должны пометить контакт как неустойчивый. Двойной проверенный замок разбит без него, и даже с изменчивым он сломан для java 1.4 и ранее – jassuncao

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 
1

dhiller является классической перепроверил замок ошибки, не использовать.