2009-03-23 13 views
2

最後のフィールドの遅延インスタンス化は可能ですか?最後のフィールドの遅延インスタンス化

次のコードはコンパイルされません:

public class Test{ 
    private final Connection conn; 

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

は、代替手段はありますか?

答えて

3

は、ここでは、(呼び出し可能と)メモ化を使用してそれを行うことができます一つの方法です:

クラスメモ:

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

Source

8

いいえ。最後のフィールドのポイントは、構築中に一度設定され、その後は変更されないことです。あなたのケースでは、コンパイラやVMはどのように有用な何かをconnで知ることができますか?そのプロパティだけがそれを設定できなければならないことを、どのように知っていますか?

おそらく、セマンティクスをどのようにしたいのかを説明した場合、代替手段を思いつくことができます。潜在的に値を取得する方法を表す「プロバイダー」インターフェースを持つことができ、別のプロバイダーにプロキシするMemoizingProviderがありますが、それ以外の場合は値を1回キャッシュします。キャッシュされた値の最終フィールドを持つことはできませんが、少なくとも1つの場所にしか存在しません。

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

私は "connの" フィールド上のfinal修飾子は右、タイプミスでしょうか?推測 – Nicolas

+5

connをvolatileとマークする必要があります。ダブルチェックされたロックはそれなしでは壊れており、揮発性であっても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の答えは、古典的な二重のチェックをロックするバグですが、は使用しません。

関連する問題