Initialisation Statique Blocs
-
19-09-2019 - |
Question
Que j'ai compris le "bloc d'initialisation statique" est utilisé pour définir les valeurs de champ statique si elle ne peut pas être fait en une seule ligne.
Mais je ne comprends pas pourquoi nous avons besoin d'un bloc spécial pour cela.Par exemple, nous déclarons un champ statique (sans affectation de la valeur).Et puis écrire plusieurs lignes de code qui génère et assigner une valeur à la ci-dessus a déclaré champ statique.
Pourquoi avons-nous besoin de ces lignes dans un bloc spécial comme: static {...}
?
La solution
bloc non statique:
{
// Do Something...
}
est appelée chaque fois une instance de la classe est construite. bloc statique n'est appelée une fois , lorsque la classe elle-même est initialisé, 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
Autres conseils
Si elles ne sont pas dans un bloc d'initialisation statique, où seraient-ils? Comment voulez-vous déclarer une variable qui était uniquement destinée à être locale aux fins de l'initialisation et le distinguer d'un terrain? Par exemple, comment 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
ne sont pas dans un bloc, ils regarderait comme les champs. Si elles étaient dans un bloc sans static
devant elle, qui compterait comme un bloc d'initialisation de l'instance au lieu d'un bloc d'initialisation statique, il serait exécuté une fois par exemple construit plutôt qu'une fois au total.
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 attribuer dans le même bloc, ou pas (par exemple si vous voulez juste quelque chose connecter - ou peut-être initialiser une bibliothèque native).
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 section « statique » (s) sera exécutée au moment du chargement de la classe, avant que les instances de la classe sont construites (et avant toutes les méthodes statiques sont appelées d'ailleurs). De cette façon, vous pouvez vous assurer que les ressources de la classe sont prêtes à l'emploi.
Il est aussi possible d'avoir des blocs de initialiseur non statiques. Ceux-ci agissent comme des extensions à l'ensemble des méthodes de constructeur définies pour la classe. Ils ressemblent à des blocs statiques initialiseur, sauf le mot-clé « statique » reste éteint.
Il est également utile lorsque vous ne voulez pas vraiment affecter la valeur à quoi que ce soit, comme le chargement de certaines classes une seule fois pendant l'exécution.
par exemple.
static {
try {
Class.forName("com.example.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
}
}
Hey, il y a un autre avantage, vous pouvez l'utiliser pour gérer les exceptions. Imaginez que getStuff()
jette ici un Exception
qui vraiment appartient dans un bloc catch:
private static Object stuff = getStuff(); // Won't compile: unhandled exception.
alors un initialiseur static
est utile ici. Vous pouvez gérer l'exception là.
Un autre exemple est de faire des choses après qui ne peut être fait au cours de l'affectation:
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, un pilote JDBC décent se fait également l'utilisation de l'initialiseur static
s'inscrire dans le DriverManager
. Voir aussi cette et cette réponse .
Je dirais que static block
est juste du sucre syntaxique. Il n'y a rien que vous pourriez faire avec bloc static
et non pas avec quoi que ce soit d'autre.
Pour réutiliser quelques exemples publiés ici.
Ce morceau de code pourrait être réécrite sans utiliser de static
initialiseur.
Méthode n ° 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;
}
Il y a quelques raisons réelles qu'il est nécessaire d'exister:
- membres de
static final
d'initialisation dont l'initialisation pourrait lancer une exception - initialisant membres de
static final
avec les valeurs calculées
Les gens ont tendance à utiliser des blocs de static {}
comme un moyen pratique pour initialiser les choses que la classe dépend au sein de l'exécution ainsi - comme assurant cette classe particulière est chargé (par exemple, les pilotes JDBC). Cela peut se faire par d'autres moyens; Cependant, les deux choses que je mentionne ci-dessus ne peut être fait avec une construction comme le bloc static {}
.
Vous pouvez exécuter des morceaux de code une fois pour une classe avant qu'un objet soit construit dans les blocs statiques.
par exemple.
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());
}
}
C'est une idée fausse commune à penser qu'un bloc statique a seulement accès à des champs statiques.Pour cela, je voudrais montrons ci-dessous un bout de code que j'ai très souvent utilisés dans le cadre des projets de vie (copié en partie de la 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
), à la carte d'un ensemble d'alias à l'origine d'un type enum.Il est conçu comme une extension à la méthode valueOf fournis par le Enum
lui-même.
Comme vous pouvez le voir, l'initialiseur statique accède à même le private
champ aliases
.Il est important de comprendre que l' static
bloc a déjà accès à la Enum
la valeur des instances (p. ex. ENGLISH
).C'est parce que l' ordre de l'initialisation et l'exécution dans le cas de Enum
types, comme si la static private
les champs ont été initialisé avec les instances devant l' static
les blocs ont été appelés:
- L'
Enum
les constantes qui sont implicites champs statiques.Cela nécessite l'Enum constructeur de l'instance et de blocs, et de l'instance, l'initialisation de se produire en premier ainsi. static
bloc et l'initialisation des champs statiques dans l'ordre d'occurrence.
Ce hors-de-l'initialisation de la commande (constructeur avant static
block) est important à noter.Il arrive aussi lorsque nous initialiser les champs statiques avec les instances de la même façon à 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 la sortie suivante:
Static Block 1
Constructor
Static Block 2
In Main
Constructor
Clair, c'est que l'initialisation statique peut effectivement arriver avant le constructeur, et même après:
Le simple accès Foo dans la méthode main, les causes de la classe de chargement et l'initialisation statique pour commencer.Mais dans le cadre de l'initialisation Statique, nous appelons à nouveau les constructeurs pour les champs statiques, après quoi il reprend initialisation statique, et complète le constructeur appelé à partir de la méthode main.Situation assez complexe pour lequel, je l'espère, dans des conditions normales de codage, nous n'aurions pas à faire face.
Pour plus d'informations sur ce sujet voir le livre "Efficace Java".
Si vos variables statiques doivent être définies lors de l'exécution puis un bloc de static {...}
est très utile.
Par exemple, si vous devez définir l'organe statique à une valeur qui est stockée dans un fichier de configuration ou base de données.
Aussi utile lorsque vous souhaitez ajouter des valeurs à un membre de Map
statique que vous ne pouvez pas ajouter ces valeurs dans la déclaration de membre initial.
Vous avez donc un champ statique (il est aussi appelé « variable de classe », car 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 un objet) et que vous voulez initialiser. Donc, si vous ne voulez pas créer une instance de cette classe et que vous voulez manipuler ce champ statique, vous pouvez le faire de trois façons:
1- initialiser Juste quand vous déclarez la variable:
static int x = 3;
2- avoir un bloc d'initialisation statique:
static int x;
static {
x=3;
}
3- disposer d'une méthode de classe (méthode statique) qui accède à la variable de classe et l'initialise: Telle 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;
}
Maintenant, pourquoi voulez-vous utiliser le bloc d'initialisation statique au lieu de méthodes statiques?
Il est vraiment à ce que vous avez besoin dans votre programme. Mais vous devez savoir que le bloc d'initialisation statique est appelé une fois le seul avantage de la méthode de classe est qu'ils peuvent être réutilisés plus tard si vous devez réinitialiser la variable de classe.
disons que vous avez un ensemble complexe dans votre programme. Vous lsinitialisez (en utilisant pour boucle par exemple) et les valeurs de ce tableau changeront tout au long du programme mais à un moment donné que vous voulez réinitialiser (revenir à la valeur initiale). Dans ce cas, vous pouvez appeler la méthode statique privée. Si vous n'avez pas besoin dans votre programme pour réinitialiser les valeurs, vous pouvez simplement utiliser le bloc statique et pas besoin d'une méthode statique puisque tu ne vas pas l'utiliser plus tard dans le programme.
Note: 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
}
}
Comme supplémentaire, comme @Pointy dit
Le code dans la section « statique » (s) sera exécutée à la charge de la classe temps, avant sont réalisés toutes les instances de la classe (et avant les méthodes statiques sont appelées d'ailleurs).
Il est censé ajouter System.loadLibrary("I_am_native_library")
dans le bloc statique.
static{
System.loadLibrary("I_am_a_library");
}
Il garantira aucune méthode native être appelée avant la bibliothèque associée est chargée en mémoire.
static int B,H;
static boolean flag = true;
static{
Scanner scan = new Scanner(System.in);
B = scan.nextInt();
scan.nextLine();
H = scan.nextInt();
if(B < 0 || H < 0){
flag = false;
System.out.println("java.lang.Exception: Breadth and height must be positive");
}
}
bloc statique est utilisé pour toute la technologie pour initialiser le membre de données statiques de manière dynamique, ou nous pouvons dire pour l'initialisation dynamique de membre de données statique bloc statique est d'être used..Because pour l'initialisation de membre de données non statique, nous avons constructeur, mais nous ne pas lieu où l'on peut 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 statique int x REINITIALISERA dynamiquement ..Bcoz lorsque le compilateur ira à Solution.x il charge Solution de classe et la charge de bloc statique au chargement de classe time..So nous pouvons en mesure d'initialiser dynamiquement membre de données statiques ..
}