114 votes

Utilisation d'initialisateurs vs constructeurs en Java

J'ai donc été le brossage de mes compétences Java comme de la fin et ont trouvé un certain nombre de fonctionnalités que je ne connaissais pas auparavant. Statique et de l'Instance Initialiseurs sont deux de ces techniques.

Ma question est de savoir quand serait-on utiliser un initialiseur au lieu d'inclure le code dans un constructeur? J'ai pensé à un couple des possibilités évidentes:

  • statique/instance initialiseurs peut être utilisé pour définir la valeur de "finale" statique/variables d'instance alors qu'un constructeur ne peut pas

  • les initialiseurs statiques peuvent être utilisées pour définir la valeur de toutes les variables statiques dans une classe, qui devrait être plus efficace que d'avoir un "si (someStaticVar == null) // faire quelque chose" bloc de code au début de chaque constructeur

Deux de ces cas, supposons que le code nécessaire à l'ensemble de ces variables est plus complexe qu'une simple "variable = valeur", sinon il n'y aurait pas de raison d'utiliser un initialiseur au lieu de simplement la définition de la valeur lors de la déclaration de la variable.

Cependant, alors que ce ne sont pas trivial gains (surtout la possibilité de définir une variable finale), il semble qu'il y a un nombre assez limité de situations dans lesquelles un initialiseur doit être utilisé.

On peut certainement utiliser un initialiseur pour beaucoup de ce qui est fait dans un constructeur, mais je ne vois vraiment pas la raison de le faire. Même si tous les constructeurs d'une classe partagent une grande quantité de code, l'utilisation d'un privé fonction initialize() semble faire plus de sens pour moi que d'utiliser un initialiseur, car il n'est pas de vous enfermer dans avoir que le code exécuté lors de l'écriture d'un nouveau constructeur.

Ai-je raté quelque chose? Il y a un certain nombre d'autres situations dans lesquelles un initialiseur doit être utilisé? Ou est-il vraiment juste assez limitée de l'outil pour être utilisé dans des situations très spécifiques?

65voto

Alex Martelli Points 330805

Les classes internes anonymes ne peuvent pas avoir de constructeur (car elles sont anonymes), elles sont donc tout à fait adaptées aux initialiseurs.

64voto

Eddie Points 27755

Les initialiseurs statiques sont utiles en tant que cletus mentionné et je les utilise de la même manière. Si vous avez une variable statique qui doit être initialisée lorsque la classe est chargée, puis un initialiseur statique est la voie à suivre, surtout qu'il permet de faire un complexe d'initialisation et ont encore la statique de la variable final. C'est une grande victoire.

Je trouve que "si (someStaticVar == null) // faire quelque chose" pour être salissant et sujettes à erreur. Si elle est initialisée de manière statique et déclarée final, alors vous éviter la possibilité d' null.

Cependant, je suis confus quand vous dites:

statique/instance initialiseurs peut être utilisé pour définir la valeur de "finale" statique/variables d'instance alors qu'un constructeur ne peut pas

Je suppose que vous dites à la fois:

  • les initialiseurs statiques peuvent être utilisées pour définir la valeur de la "finale" des variables statiques, alors qu'un constructeur ne peut pas
  • exemple initialiseurs peut être utilisée pour définir la valeur de la "finale" de variables d'instance, alors qu'un constructeur ne peut pas

et vous avez raison sur le premier point, le mal, sur la deuxième. Vous pouvez, par exemple, faire ceci:

class MyClass {
    private final int counter;
    public MyClass(final int counter) {
        this.counter = counter;
    }
}

Aussi, quand il y a beaucoup de code est partagé entre les constructeurs, l'une des meilleures façons de le gérer est de la chaîne des constructeurs, en fournissant les valeurs par défaut. Ce fait est assez clair sur ce qui est fait:

class MyClass {
    private final int counter;
    public MyClass() {
        this(0);
    }
    public MyClass(final int counter) {
        this.counter = counter;
    }
}

27voto

cletus Points 276888

J'ai le plus souvent l'utilisation d'initialiseur statique blocs pour la mise en place finale des données statiques, en particulier des collections. Par exemple:

public class Deck {
  private final static List<String> SUITS;

  static {
    List<String> list = new ArrayList<String>();
    list.add("Clubs");
    list.add("Spades");
    list.add("Hearts");
    list.add("Diamonds");
    SUITS = Collections.unmodifiableList(list);
  }

  ...
}

Désormais cet exemple peut être fait avec une seule ligne de code:

private final static List<String> SUITS =
  Collections.unmodifiableList(
    Arrays.asList("Clubs", "Spades", "Hearts", "Diamonds")
  );

mais la version statique peut être beaucoup plus soignée, en particulier lorsque les éléments sont non négligeable pour l'initialiser.

Une implémentation naïve peut aussi ne pas créer un inmodifiable liste, ce qui est un risque d'erreur. Le ci-dessus crée un immuable structure de données que vous pouvez heureusement de retour à partir de méthodes publiques et ainsi de suite.

16voto

Robin Points 15032

Juste pour ajouter à certains déjà d'excellents points ici. L'initialiseur statique est thread-safe. Elle est exécutée lorsque la classe est chargée, et donc rend plus simple pour les données statiques de l'initialisation de l'aide d'un constructeur, dans lequel vous auriez besoin d'un bloc synchronisé pour vérifier si les données statiques est initialisé et puis l'initialiser.

public class MyClass {

    static private Properties propTable;

    static
    {
        try 
        {
            propTable.load(new FileInputStream("/data/user.prop"));
        } 
        catch (Exception e) 
        {
            propTable.put("user", System.getProperty("user"));
            propTable.put("password", System.getProperty("password"));
        }
    }

rapport

public class MyClass 
{
    public MyClass()
    {
        synchronized (MyClass.class) 
        {
            if (propTable == null)
            {
                try 
                {
                    propTable.load(new FileInputStream("/data/user.prop"));
                } 
                catch (Exception e) 
                {
                    propTable.put("user", System.getProperty("user"));
                    propTable.put("password", System.getProperty("password"));
                }
            }
        }
    }

N'oubliez pas, vous avez maintenant de se synchroniser à la classe, pas le niveau de l'instance. Cela engendre un coût pour chaque instance construit à la place d'un coût de temps lorsque la classe est chargée. De Plus, c'est moche ;-)

13voto

Daniel Points 361

J'ai lu tout un article à la recherche d'une réponse à l'ordre d'initialisation des initialiseurs par rapport à leurs constructeurs. Je ne l'ai pas trouvé, alors j'ai écrit du code pour vérifier ma compréhension. Je pensais ajouter cette petite démonstration en commentaire. Pour tester votre compréhension, voyez si vous pouvez prédire la réponse avant de la lire en bas.

 /**
 * Demonstrate order of initialization in Java.
 * @author Daniel S. Wilkerson
 */
public class CtorOrder {
  public static void main(String[] args) {
    B a = new B();
  }
}

class A {
  A() {
    System.out.println("A ctor");
  }
}

class B extends A {

  int x = initX();

  int initX() {
    System.out.println("B initX");
    return 1;
  }

  B() {
    super();
    System.out.println("B ctor");
  }

}
 

Sortie:

 java CtorOrder
A ctor
B initX
B ctor
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X