Blocs D'Initialisation Statique

d'après ce que j'ai compris, le" bloc d'initialisation statique " est utilisé pour définir les valeurs du champ statique s'il ne peut pas être fait sur une ligne.

Mais je ne comprends pas pourquoi nous avons besoin d'un bloc spécial pour cela. Par exemple, nous déclarons un champ comme statique (sans assignation de valeur). Puis écrivez plusieurs lignes du code qui génèrent et assignent une valeur au champ statique déclaré ci-dessus.

Pourquoi avons-nous besoin de ces lignes dans un bloc spécial comme: static {...} ?

225
demandé sur Andrew Tobilko 2010-03-10 23:37:35

13 réponses

le bloc non statique:

{
    // Do Something...
}

est appelé chaque fois une instance de la classe est construite. Le bloc statique n'est appelé qu'une fois , lorsque la classe elle-même est initialisée, peu importe le nombre d'objets de ce type que vous créez.

exemple:

public class Test {

    static{
        System.out.println("Static");
    }

    {
        System.out.println("Non-static block");
    }

    public static void main(String[] args) {
        Test t = new Test();
        Test t2 = new Test();
    }
}

Cette affiche:

Static
Non-static block
Non-static block
371
répondu Frederik Wordenskjold 2016-03-23 22:10:10

S'ils n'étaient pas dans un bloc d'initialisation statique, où seraient-ils? Comment décririez-vous une variable qui n'est censée être locale qu'à des fins d'initialisation, et la distingueriez-vous d'un champ? Par exemple, comment vous voulez écrire:

public class Foo {
    private static final int widgets;

    static {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        widgets = first + second;
    }
}

si first et second n'étaient pas dans un bloc, ils ressembleraient à des champs. S'ils étaient dans un bloc sans static devant lui, cela compterait comme un le bloc d'initialisation d'instance au lieu d'un bloc d'initialisation statique, donc il serait exécuté une fois par instance construite plutôt qu'une fois au total.

Maintenant, dans ce cas particulier, vous pouvez utiliser une méthode statique à la place:

public class Foo {
    private static final int widgets = getWidgets();

    static int getWidgets() {
        int first = Widgets.getFirstCount();
        int second = Widgets.getSecondCount();
        // Imagine more complex logic here which really used first/second
        return first + second;
    }
}

... mais cela ne fonctionne pas quand il y a plusieurs variables que vous souhaitez affecter dans le même bloc, ou Aucune (par exemple si vous voulez juste enregistrer quelque chose - ou peut-être Initialiser une bibliothèque native).

115
répondu Jon Skeet 2015-06-10 05:47:56

voici un exemple:

  private static final HashMap<String, String> MAP = new HashMap<String, String>();
  static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

le code dans la(Les) section (S)" statique (s) " sera exécuté au moment de la charge de la classe, avant que toute instance de la classe soit construite (et avant que toute méthode statique soit appelée d'ailleurs). De cette façon vous pouvez vous assurer que les ressources de classe sont toutes prêtes à l'emploi.

il est également possible d'avoir des blocs d'initialisation non statiques. Ceux-ci agissent comme des extensions à l'ensemble des méthodes de constructeur définies pour le classe. Elles ressemblent initialiseur statique blocs, sauf le mot-clé "static" est laissé de côté.

90
répondu Pointy 2010-03-10 20:48:53

c'est aussi utile quand vous ne voulez pas assigner la valeur à quoi que ce soit, comme charger une certaine classe une seule fois pendant l'exécution.

E. G.

static {
    try {
        Class.forName("com.example.jdbc.Driver");
    } catch (ClassNotFoundException e) {
        throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
    }
}

Hé, il y a un autre avantage, vous pouvez l'utiliser pour gérer les exceptions. Imaginez que getStuff() lance ici un Exception qui vraiment appartient à un bloc catch:

private static Object stuff = getStuff(); // Won't compile: unhandled exception.

puis un static initialiseur est utile ici. Vous pouvez gérer l'exception.

un autre exemple est de faire des choses par la suite qui ne peuvent pas être faites lors de l'assignation:

private static Properties config = new Properties();

static {
    try { 
        config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
    } catch (IOException e) {
        throw new ExceptionInInitializerError("Cannot load properties file.", e);
    }
}

pour revenir à L'exemple du pilote JDBC, tout pilote JDBC décent lui-même utilise également l'initialiseur static pour s'enregistrer dans le DriverManager . Voir aussi ce et ce réponse.

44
répondu BalusC 2017-05-23 12:02:47

je dirais static block est juste du sucre syntaxique. Il n'y a rien que vous pourriez faire avec static bloc et pas avec quoi que ce soit d'autre.

pour réutiliser quelques exemples affichés ici.

ce morceau de code pourrait être réécrit sans utiliser l'initialiseur static .

Méthode #1: Avec static

private static final HashMap<String, String> MAP;
static {
    MAP.put("banana", "honey");
    MAP.put("peanut butter", "jelly");
    MAP.put("rice", "beans");
  }

Méthode #2: Sans static

private static final HashMap<String, String> MAP = getMap();
private static HashMap<String, String> getMap()
{
    HashMap<String, String> ret = new HashMap<>();
    ret.put("banana", "honey");
    ret.put("peanut butter", "jelly");
    ret.put("rice", "beans");
    return ret;
}
11
répondu user1508893 2013-02-28 05:20:49

il y a quelques raisons réelles pour lesquelles elle doit exister:

  1. initialisation static final les membres dont l'initialisation peut lever une exception
  2. initialisation static final membres avec les valeurs calculées

les gens ont tendance à utiliser static {} blocs comme un moyen pratique d'initialiser les choses dont la classe dépend dans le runtime ainsi - tels que s'assurer que la classe particulière est chargé (par exemple, les pilotes JDBC). Cela peut être fait d'autres façons; cependant, les deux choses que je mentionne ci-dessus ne peuvent être faites qu'avec une construction comme le bloc static {} .

9
répondu D.Shawley 2012-09-07 11:43:39

vous pouvez exécuter des bits de code une fois pour une classe avant qu'un objet ne soit construit dans les blocs statiques.

E. G.

class A {
  static int var1 = 6;
  static int var2 = 9;
  static int var3;
  static long var4;

  static Date date1;
  static Date date2;

  static {
    date1 = new Date();

    for(int cnt = 0; cnt < var2; cnt++){
      var3 += var1;
    }

    System.out.println("End first static init: " + new Date());
  }
}
7
répondu Pierre-Antoine LaFayette 2010-03-10 20:46:00

c'est une idée fausse courante de penser qu'un bloc statique n'a accès qu'à des champs statiques. Pour cela je voudrais montrer ci-dessous morceau de code que j'utilise assez souvent dans les projets de la vie réelle (copié en partie de une autre réponse dans un contexte légèrement différent):

public enum Language { 
  ENGLISH("eng", "en", "en_GB", "en_US"),   
  GERMAN("de", "ge"),   
  CROATIAN("hr", "cro"),   
  RUSSIAN("ru"),
  BELGIAN("be",";-)");

  static final private Map<String,Language> ALIAS_MAP = new HashMap<String,Language>(); 
  static { 
    for (Language l:Language.values()) { 
      // ignoring the case by normalizing to uppercase
      ALIAS_MAP.put(l.name().toUpperCase(),l); 
      for (String alias:l.aliases) ALIAS_MAP.put(alias.toUpperCase(),l); 
    } 
  } 

  static public boolean has(String value) { 
    // ignoring the case by normalizing to uppercase
    return ALIAS_MAP.containsKey(value.toUpper()); 
  } 

  static public Language fromString(String value) { 
    if (value == null) throw new NullPointerException("alias null"); 
    Language l = ALIAS_MAP.get(value); 
    if (l == null) throw new IllegalArgumentException("Not an alias: "+value); 
    return l; 
  } 

  private List<String> aliases; 
  private Language(String... aliases) { 
    this.aliases = Arrays.asList(aliases); 
  } 
} 

ici, l'initialiseur est utilisé pour maintenir un index ( ALIAS_MAP ), pour mapper un ensemble d'alias de retour au type original enum. Il est conçu comme un extension à la valeur intégrée de la méthode fournie par le Enum lui-même.

comme vous pouvez le voir, l'initialiseur statique accède même au champ private . Il est important de comprendre que le bloc static a déjà accès aux instances de valeur Enum (par exemple ENGLISH ). C'est parce que l'ordre d'initialisation et d'exécution dans le cas de Enum types , tout comme si les champs static private ont été initialisés avec des instances avant que les blocs static aient été appelés:

  1. les constantes Enum qui sont des champs statiques implicites. Cela nécessite le constructeur D'Enum et les blocs d'instance, et l'initialisation de l'instance pour se produire en premier.
  2. static bloquer et d'initialisation des champs statiques dans l'ordre d'occurrence.

Ce hors-de-l'initialisation de la commande (constructeur avant static bloc) est important à noter. Cela se produit aussi lorsque nous initialisons des champs statiques avec les instances semblables à un Singleton (simplifications faites):

public class Foo {
  static { System.out.println("Static Block 1"); }
  public static final Foo FOO = new Foo();
  static { System.out.println("Static Block 2"); }
  public Foo() { System.out.println("Constructor"); }
  static public void main(String p[]) {
    System.out.println("In Main");
    new Foo();
  }
}

ce que nous voyons est le résultat suivant:

Static Block 1
Constructor
Static Block 2
In Main
Constructor

clair est que l'initialisation statique peut effectivement se produire avant le constructeur, et même après:

simplement accéder à Foo dans la main méthode, permet de charger la classe et de démarrer l'initialisation statique. Mais dans le cadre de l'initialisation statique nous appelons de nouveau les constructeurs pour les champs statiques, après quoi il reprend l'initialisation statique, et complète le constructeur appelé dans la méthode principale. Une situation assez complexe pour laquelle j'espère que nous n'aurons pas à nous occuper dans un codage normal.

pour plus d'informations sur ce voir le livre " Java efficace ".

6
répondu YoYo 2018-02-06 21:13:33

si vos variables statiques doivent être réglées à l'exécution, alors un bloc static {...} est très utile.

par exemple, si vous avez besoin de définir le membre statique à une valeur qui est stockée dans un fichier de configuration ou une base de données.

est également utile lorsque vous voulez ajouter des valeurs à un membre Map statique car vous ne pouvez pas ajouter ces valeurs dans la déclaration de membre initiale.

3
répondu Marcus Leon 2010-03-10 20:40:51

Donc, vous avez un champ statique (c'est aussi appelée "variable de classe" parce qu'il appartient à la classe plutôt qu'à une instance de la classe; en d'autres termes, il est associé à la classe plutôt qu'avec n'importe quel objet) et que vous souhaitez initialiser. Donc, si vous ne voulez PAS créer une instance de cette classe et que vous souhaitez manipuler ce champ statique, vous pouvez le faire de trois façons:

1-Il suffit de l'initialiser lorsque vous déclarez la variable:

static int x = 3;

2 - ont un bloc d'initialisation statique:

static int x;

static {
 x=3;
}

3 - une méthode de classe (méthode statique) qui accède à la variable de classe et l'initialise: c'est l'alternative au bloc statique ci-dessus; vous pouvez écrire une méthode statique privée:

public static int x=initializeX();

private static int initializeX(){
 return 3;
}

Pourquoi utiliser un bloc d'initialisation statique plutôt que des méthodes statiques?

c'est vraiment à la hauteur de ce dont vous avez besoin dans votre programme. Mais vous devez savoir que statique initialisation du bloc est appelé une fois et le seul avantage de la méthode de classe est qu'ils peuvent être réutilisés plus tard si vous avez besoin de réinitialiser la variable de classe.

disons que vous avez un tableau complexe dans votre programme. Vous l'initialisez (en utilisant pour boucle par exemple) et puis les valeurs dans ce tableau changeront tout au long du programme mais à un certain point vous voulez le réinitialiser (revenir à la valeur initiale). Dans ce cas, vous pouvez appeler le méthode statique privée. Dans le cas où vous n'avez pas besoin dans votre programme pour réinitialiser les valeurs, vous pouvez utiliser le bloc statique et pas besoin d'une méthode statique puisque tu ne vas pas l'utiliser plus tard dans le programme.

Remarque: les blocs statiques sont appelés, dans l'ordre où ils apparaissent dans le code.

exemple 1:

class A{
 public static int a =f();

// this is a static method
 private static int f(){
  return 3;
 }

// this is a static block
 static {
  a=5;
 }

 public static void main(String args[]) {
// As I mentioned, you do not need to create an instance of the class to use the class variable
  System.out.print(A.a); // this will print 5
 }

}

exemple 2:

class A{
 static {
  a=5;
 }
 public static int a =f();

 private static int f(){
  return 3;
 }

 public static void main(String args[]) {
  System.out.print(A.a); // this will print 3
 }

}
2
répondu Randa Sbeity 2013-07-29 03:51:15

comme supplémentaire, comme @Pointy a dit

le code dans la(Les) section (S)" statique (s) " sera exécuté à la charge de classe temps, avant que toutes les instances de la classe sont construites (et avant toutes les méthodes statiques sont appelés d'ailleurs).

il est supposé ajouter System.loadLibrary("I_am_native_library") dans le bloc statique.

static{
    System.loadLibrary("I_am_a_library");
}

il garantit qu'aucune méthode native ne sera appelée avant le chargement de la bibliothèque correspondante dans la mémoire.

selon loadLibrary d'oracle :

Si cette méthode est appelée plusieurs fois avec le même nom de bibliothèque, le deuxième appel et les suivants sont ignorés.

donc tout à fait inopinément, système de putting.loadLibrary n'est pas utilisé pour éviter que la bibliothèque soit chargée plusieurs fois.

0
répondu Gearon 2016-08-03 14:18:51

vous devez d'abord comprendre que vos classes d'application elles-mêmes sont instanciées aux objets java.class.Class pendant l'exécution. C'est quand vos blocs statiques sont lancés. Donc vous pouvez réellement faire ceci:

public class Main {

    private static int myInt;

    static {
        myInt = 1;
        System.out.println("myInt is 1");
    }

    //  needed only to run this class
    public static void main(String[] args) {
    }

}

et il imprimerait" myInt est 1 " à la console. Notez que je n'ai instancié aucune classe.

0
répondu eosimosu 2016-10-20 16:24:31

bloc statique est utilisé pour n'importe quelle technologie pour initialiser l'élément de données statique de manière dynamique,ou nous pouvons dire pour l'initialisation dynamique de l'élément de données statique bloc statique est utilisé..Parce que pour l'initialisation de membre de données non statiques nous avons constructeur mais nous n'avons aucun endroit où nous pouvons initialiser dynamiquement membre de données statiques

Eg:-class Solution{
         // static int x=10;
           static int x;
       static{
        try{
          x=System.out.println();
          }
         catch(Exception e){}
        }
       }

     class Solution1{
      public static void main(String a[]){
      System.out.println(Solution.x);
        }
        }

maintenant mon int x statique va s'initialiser dynamiquement ..Bcoz quand compilateur ira à la Solution.x il se chargera Classe de Solution et charge de bloc statique au temps de chargement de classe..de sorte que nous pouvons dynamiquement initialiser ce membre de données statique..

}

-1
répondu Arun 2012-10-14 16:45:21