Java: Quand un bloc d'initialisation statique est-il utile?

91

Quelle est la différence entre l'initialisation dans un staticbloc:

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

Et initialisation statique individuelle:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....
Adam Matan
la source
1
Vous n'utilisez que des affectations dans le bloc d'initialisation statique, donc bien sûr, celles-ci pourraient être effectuées en utilisant une affectation de variable statique. Avez-vous essayé de voir ce qui se passe si vous devez exécuter des instructions de non-affectation?
Platinum Azure
C'est un bon endroit pour charger des classes ou charger une bibliothèque native.
qrtt1
1
Notez que les variables statiques doivent être évitées et par conséquent, les blocs d'initialisation statiques ne sont généralement pas une bonne idée. Si vous vous retrouvez à les utiliser beaucoup, attendez-vous à des problèmes sur toute la ligne.
Bill K

Réponses:

106

Un bloc d'initialisation statique permet une initialisation plus complexe, par exemple à l'aide de conditions:

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

Ou lorsque plus qu'une simple construction est requise: lorsque vous utilisez un générateur pour créer votre instance, une gestion des exceptions ou un travail autre que la création de champs statiques est nécessaire.

Un bloc d'initialisation statique s'exécute également après les initialiseurs statiques en ligne, de sorte que ce qui suit est valide:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}
Rich O'Kelly
la source
3
Faire "b = a * 4;" inline ne poserait problème que si b était déclaré avant a, ce qui n'est pas le cas dans votre exemple.
George Hawkins
1
@GeorgeHawkins J'essayais seulement d'illustrer qu'un initialiseur statique s'exécute après des initialiseurs en ligne, pas qu'un équivalent ne puisse pas être fait en ligne. Cependant, je comprends votre point de vue et j'ai mis à jour l'exemple pour (espérons-le) être plus clair.
Rich O'Kelly
1
Juste pour le plaisir, je pourrais souligner que votre premier exemple pourrait tout aussi bien être "static double a = someCondition? 0: 1;" Non pas que vos exemples ne soient pas géniaux, je dis juste ... :)
Bill K
18

Une utilisation typique:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

Comment feriez-vous cela sans initialiseur statique?

gawi
la source
2
Réponse: Guava :) +1
Paul Bellora
2
Autre réponse sans bibliothèques supplémentaires: créez une méthode statique qui encapsule l'initialisation SETet utilisez la variable initializer ( private final static Set<String> SET = createValueSet()). Et si vous aviez 5 ensembles et 2 cartes, les videriez-vous tous dans un seul staticbloc?
TWiStErRob
14

Vous pouvez utiliser le bloc try / catch à l'intérieur static{}comme ci-dessous:

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PS: référé de cela !

Karan Patel
la source
11

La gestion des exceptions lors de l'initialisation est une autre raison. Par exemple:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

Ceci est utile pour les constructeurs qui lancent de manière ennuyeuse des exceptions vérifiées, comme ci-dessus, ou pour une logique d'initialisation plus complexe qui pourrait être sujette aux exceptions.

Paul Bellora
la source
5

Parfois, vous souhaitez faire plus que simplement affecter des valeurs à des variables statiques. Puisque vous ne pouvez pas placer d'instructions arbitraires dans le corps de la classe, vous pouvez utiliser un bloc d'initialisation statique.

Jesper
la source
4

Dans votre exemple, il n'y a pas de différence; mais souvent la valeur initiale est plus complexe que ce qui est confortablement exprimé dans une seule expression (par exemple, c'est un List<String>dont le contenu est mieux exprimé par un for-loop; ou c'est un Methodqui peut ne pas exister, donc des gestionnaires d'exceptions sont nécessaires), et / ou les champs statiques doivent être définis dans un ordre spécifique.

Ruakh
la source
4

staticblock peut être utilisé pour initialiser l' instance singleton , pour éviter d'utiliser la méthode synchronisée getInstance() .

Marin danubien
la source
3

Techniquement, vous pourriez vous en passer. Certains préfèrent le code d'initialisation multiligne pour entrer dans une méthode statique. Je suis assez content d'utiliser un initialiseur statique pour une initialisation relativement simple à plusieurs états.

Bien sûr, je faisais presque toujours ma statique finalet je pointerais vers un objet non modifiable.

Tom Hawtin - Tacle
la source
3

Le mot-clé statique (qu'il s'agisse d'une variable ou d'un bloc) appartient à la classe. Ainsi, lorsque la classe est appelée, ces variables ou blocs sont exécutés. La plupart de l'initialisation se fera donc à l'aide d'un mot-clé statique. Comme il appartient à la classe elle-même, la classe peut y accéder directement, sans créer une instance de la classe.

Prenons un exemple, il existe une classe de chaussures dans laquelle il y a plusieurs variables comme la couleur, la taille, la marque etc ... Et ici, si l'entreprise de fabrication de chaussures n'a qu'une seule marque, nous devrions l'initialiser en tant que variable statique. Ainsi, lorsque la classe de chaussures est appelée et que différents types de chaussures sont fabriqués (en créant une instance de la classe) à ce moment-là, la couleur et la taille occuperont la mémoire chaque fois qu'une nouvelle chaussure est créée, mais ici la marque est une propriété commune à toutes les chaussures, afin qu'il occupe la mémoire pour une fois, quel que soit le nombre de chaussures fabriquées.

Exemple:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}
imbiber
la source
1

Nous utilisons des constructeurs pour initialiser nos variables d'instance (variables non statiques, variables qui appartiennent à des objets, pas à la classe).

Si vous souhaitez initialiser des variables de classe (variables statiques) et que vous voulez le faire sans créer d'objet (les constructeurs ne peuvent être appelés que lors de la création d'un objet), vous avez besoin de blocs statiques.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}
Michael
la source
La lecture de stdin dans un initialiseur statique est une idée assez horrible. Et System.out.println("B * H");c'est assez inutile. Et la réponse elle-même est assez vague. OP n'a pas mentionné les constructeurs ou les variables d'instance.
shmosel
Ceci est juste un exemple qui montre ce qu'est un initialiseur statique et comment il est utilisé. OP n'a pas demandé de constructeurs ou de variables d'instance, mais pour lui apprendre la différence entre l'initialiseur statique et le constructeur, il doit le savoir. Sinon, il dirait "Pourquoi est-ce que je n'utilise pas simplement un constructeur pour initialiser mes variables statiques?"
Michael
0

Le bloc de code statique permet d'initialiser les champs avec plus que l'instuction, d'initialiser les champs dans un ordre différent des déclarations et pourrait également être utilisé pour l'initialisation conditionnelle.

Plus précisement,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

ne fonctionnera pas car a et b sont déclarés après ab.

Cependant, je pourrais utiliser un init statique. bloquer pour surmonter cela.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}
algolicieux
la source
3
Bien que ce que vous dites soit vrai, cela ne démontre pas la nécessité d'un bloc d'initialisation statique. Vous pouvez simplement déplacer votre abdéclaration sous la déclaration de b.
gawi
0

Un bloc d'initialisation statique est utile si vous souhaitez initialiser les types statiques de classe spécifiés, avant la première utilisation de la classe. Une utilisation ultérieure n'invoquera aucun bloc d'initialisation statique. C'est l'opposé direct des initialiseurs d'instance, qui initialisent les membres d'instance.

Remario
la source
0

Lorsque vous souhaitez évaluer une certaine expression pendant le temps de chargement de la classe, vous pouvez utiliser un bloc statique, mais rappelez-vous:

Vous devez gérer une exception dans un bloc statique, ce qui signifie que vous ne pouvez pas lever d'exception à partir d'un bloc statique.

Je suis_Pratik
la source