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?
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.
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 ...
static { ... }
dans une classe Java. et exécuté par la machine virtuelle lorsque la classe est appelée.return
n'est prise en charge.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!
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");
}
}
Ceci est directement de http://www.programcreek.com/2011/10/Java-class-instance-initializers/
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é
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.
L'utilisation d'initialiseurs d'instance est rare, mais elle peut néanmoins constituer une alternative utile aux initialiseurs de variables d'instance si:
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.
"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.
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.
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.
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.