Question

Est-il possible d'instancier paresseusement un champ final?

Le code suivant ne compile pas:

public class Test{
    private final Connection conn;

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

Y at-il une alternative?

Était-ce utile?

La solution 2

Voici une façon que vous pouvez le faire en utilisant mémoïsation (avec appelables):

Classe Mémo:

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

Maintenant, nous pouvons créer une conn finale!

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

Autres conseils

Non. Le point d'un champ final est qu'il est fixé une fois, lors de la construction, et ne changera jamais par la suite. Comment pourrait le compilateur ou la machine virtuelle rien savoir utile sur votre cas dans conn? Comment serait-il savoir que cette propriété ne devrait être en mesure de le mettre, et non une autre méthode?

Peut-être si vous voulez ce que vous expliquez la sémantique d'être, nous pourrions arriver à un altérant. Vous pourriez éventuellement avoir une interface « fournisseur » représentant un moyen d'aller chercher une valeur, puis un des procurations à MemoizingProvider un autre fournisseur, mais une seule fois, la mise en cache de la valeur autrement. Ce ne serait pas en mesure d'avoir un champ final pour la valeur mise en cache non plus, mais au moins il ne serait en un seul endroit.

La réponse de dhiller est le bug de verrouillage revérifié classique, ne pas utiliser.

Comme dit Jon Skeet, non, il n'y a pas.

Interprétation de votre exemple de code que vous pouvez faire quelque chose comme ceci:

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

Comme une note de côté, il est possible de changer un champ final. Au moins champs d'instance. Vous avez juste besoin de réflexion:

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top