web-dev-qa-db-fra.com

Quelle est la différence entre un bloc de code d'initialisation statique et non statique

Ma question concerne une utilisation particulière du mot clé statique. Il est possible d'utiliser le mot clé static pour couvrir un bloc de code dans une classe qui n'appartient à aucune fonction. Par exemple, le code suivant est compilé:

public class Test {
    private static final int a;    
    static {
        a = 5;
        doSomething(a);
    }
    private static int doSomething(int x) {
        return (x+5);
    }
}

Si vous supprimez le mot clé static, il se plaint car la variable a est final. Cependant, il est possible de supprimer les deux mots-clés final et static et de le compiler.

C'est déroutant pour moi dans les deux sens. Comment suis-je censé avoir une section de code qui n'appartient à aucune méthode? Comment est-il possible de l'invoquer? En général, quel est le but de cet usage? Ou mieux, où puis-je trouver de la documentation à ce sujet?

335
Szere Dyeri

Le bloc de code avec le modificateur statique signifie un initialiseur classe; sans le modificateur statique, le bloc de code est un initialiseur instance.

Les initialiseurs de classe sont exécutés dans l'ordre dans lequel ils ont été définis (de haut en bas, exactement comme des initialiseurs de variables simples) lorsque la classe est chargée (en fait, lorsqu'elle est résolue, mais c'est un détail technique).

Les initialiseurs d'instance sont exécutés dans l'ordre défini lors de l'instanciation de la classe, immédiatement avant l'exécution du code constructeur, immédiatement après l'appel du super constructeur.

Si vous supprimez static de int a, il devient une variable d'instance à laquelle vous ne pouvez pas accéder à partir du bloc d'initialisation statique. La compilation avec l’erreur "Variable non statique a échouera à partir d’un contexte statique".

Si vous supprimez également static du bloc d'initialisation, celui-ci devient un initialiseur d'instance et ainsi int a est initialisé à la construction.

385
Lawrence Dol

ff! Qu'est-ce que l'initialiseur statique?

L’initialiseur statique est un bloc de code static {} situé dans la classe Java et n’est exécuté qu’une fois avant l’appel du constructeur ou de la méthode main.

OK! Dites m'en plus ...

  • est un bloc de code static { ... } dans une classe Java. et exécuté par la machine virtuelle lorsque la classe est appelée.
  • Aucune instruction return n'est prise en charge.
  • Aucun argument n'est supporté.
  • Aucun this ou super n'est pris en charge.

Hmm, où puis-je l'utiliser?

Peut être utilisé partout où vous vous sentez bien :) aussi simple que cela. Mais je vois la plupart du temps qu'il est utilisé pour la connexion à la base de données, l'API init, la journalisation, etc.

Ne vous contentez pas d'aboyer! Où est l'exemple?

package com.example.learnjava;

import Java.util.ArrayList;

public class Fruit {

    static {
        System.out.println("Inside Static Initializer.");

        // fruits array
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Pear");

        // print fruits
        for (String fruit : fruits) {
            System.out.println(fruit);
        }
        System.out.println("End Static Initializer.\n");
    }

    public static void main(String[] args) {
        System.out.println("Inside Main Method.");
    }
}

sortie ???

Initialiseur statique interne.

Apple

Orange

Poire

Fin de l'initialiseur statique.

Méthode principale intérieure.

J'espère que cela t'aides!

154
Madan Sapkota

Le bloc static est un "initialiseur statique".

Il est automatiquement appelé lorsque la classe est chargée et il n'y a pas d'autre moyen de l'invoquer (pas même via Reflection).

Personnellement, je ne l'ai utilisé que pour l'écriture de code JNI:

class JNIGlue {
    static {
        System.loadLibrary("foo");
    }
}
54
Alnitak

Ceci est directement de http://www.programcreek.com/2011/10/Java-class-instance-initializers/

1. Ordre d'exécution

Regardez le cours suivant, savez-vous lequel est exécuté en premier?

public class Foo {

    //instance variable initializer
    String s = "abc";

    //constructor
    public Foo() {
        System.out.println("constructor called");
    }

    //static initializer
    static {
        System.out.println("static initializer called");
    }

    //instance initializer
    {
        System.out.println("instance initializer called");
    }

    public static void main(String[] args) {
        new Foo();
        new Foo();
    }
}

Sortie:

initialiseur statique appelé

initialiseur d'instance appelé

constructeur appelé

initialiseur d'instance appelé

constructeur appelé

2. Comment fonctionne l'initialiseur d'instance Java?

L'initialiseur d'instance ci-dessus contient une instruction println. Pour comprendre son fonctionnement, nous pouvons le traiter comme une instruction d’affectation de variable, par exemple, b = 0. Cela peut rendre plus évident à comprendre.

Au lieu de

int b = 0, vous pourriez écrire

int b;
b = 0;

Par conséquent, les initialiseurs d'instance et les initialiseurs de variable d'instance sont à peu près les mêmes.

3. Quand les initialiseurs d'instance sont-ils utiles?

L'utilisation d'initialiseurs d'instance est rare, mais elle peut néanmoins constituer une alternative utile aux initialiseurs de variables d'instance si:

  1. Le code de l'initialiseur doit gérer les exceptions
  2. Effectuez des calculs qui ne peuvent pas être exprimés avec un initialiseur de variable d’instance.

Bien entendu, ce code pourrait être écrit dans les constructeurs. Mais si une classe avait plusieurs constructeurs, vous devrez répéter le code dans chaque constructeur.

Avec un initialiseur d'instance, vous pouvez simplement écrire le code une fois et il sera exécuté quel que soit le constructeur utilisé pour créer l'objet. (Je suppose que ce n’est qu’un concept, et il n’est pas utilisé souvent.)

Les classes internes anonymes sont un autre cas dans lequel les initialiseurs sont utiles: ils ne peuvent déclarer aucun constructeur. (Sera-ce un bon endroit pour placer une fonction de journalisation?)

Merci à Derhein.

Notez également que les classes anonymes implémentant des interfaces [1] n'ont pas de constructeur. Par conséquent, des initialiseurs d'instance sont nécessaires pour exécuter tout type d'expression au moment de la construction.

37
Alexei Fando

"final" garantit qu'une variable doit être initialisée avant la fin du code d'initialisation de l'objet. De même, "static final" garantit qu'une variable sera initialisée par le code d'initialisation de fin de classe. Omettre le "statique" de votre code d'initialisation le transforme en code d'initialisation d'objet; ainsi votre variable ne satisfait plus ses garanties.

12
DJClayworth

lorsqu'un développeur utilise un bloc d'initialisation, le compilateur Java copie l'initialiseur dans chaque constructeur de la classe actuelle.

Exemple:

le code suivant:

class MyClass {

    private int myField = 3;
    {
        myField = myField + 2;
        //myField is worth 5 for all instance
    }

    public MyClass() {
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

est équivalent à:

class MyClass {

    private int myField = 3;

    public MyClass() {
        myField = myField + 2;
        myField = myField * 4;
        //myField is worth 20 for all instance initialized with this construtor
    }

    public MyClass(int _myParam) {
        myField = myField + 2;
        if (_myParam > 0) {
            myField = myField * 4;
            //myField is worth 20 for all instance initialized with this construtor
            //if _myParam is greater than 0
        } else {
            myField = myField + 5;
            //myField is worth 10 for all instance initialized with this construtor
            //if _myParam is lower than 0 or if _myParam is worth 0
        }
    }

    public void setMyField(int _myField) {
        myField = _myField;
    }


    public int getMyField() {
        return myField;
    }
}

public class MainClass{

    public static void main(String[] args) {
        MyClass myFirstInstance_ = new MyClass();
        System.out.println(myFirstInstance_.getMyField());//20
        MyClass mySecondInstance_ = new MyClass(1);
        System.out.println(mySecondInstance_.getMyField());//20
        MyClass myThirdInstance_ = new MyClass(-1);
        System.out.println(myThirdInstance_.getMyField());//10
    }
}

J'espère que mon exemple est compris par les développeurs.

6
cardman

Vous n'écrirez pas de code dans un bloc statique qui doit être appelé n'importe où dans votre programme. Si le but du code doit être appelé, vous devez le placer dans une méthode.

Vous pouvez écrire des blocs d'initialisation statiques pour initialiser des variables statiques lorsque la classe est chargée, mais ce code peut être plus complexe.

Un bloc d'initialisation statique ressemble à une méthode sans nom, sans argument ni type de retour. Comme tu ne l'appelles jamais, il n'a pas besoin de nom. Le seul moment où elle est appelée est le moment où la machine virtuelle charge la classe.

6
Vincent Ramdhanie

Le bloc de code statique peut être utilisé pour instancier ou initialiser des variables de classe (par opposition à des variables d'objet). Ainsi, déclarer "a" statique signifie qu'il ne s'agit que d'un objet partagé par tous les objets Test et que le bloc de code statique initialise "a" une seule fois, lors du premier chargement de la classe Test, quel que soit le nombre d'objets Test créés.

4
Paul Tomblin