t
t
t
t
t t 4) Initialisation & nettoyage
tttt
4) Initialization & Cleanup
Texte original t Traducteur : F. DEFAIX et Y. CHICHA
t
t
///
Ce chapitre contient 6 pages
1 2 3 4 5 6
\\\
t t t
t t t
t
t t t
There are a number of additional speedups possible in a JVM. An especially important one involves the operation of the loader and Just-In-Time (JIT) compiler. When a class must be loaded (typically, the first time you want to create an object of that class), the .class file is located and the byte codes for that class are brought into memory. At this point, one approach is to simply JIT all the code, but this has two drawbacks: it takes a little more time, which, compounded throughout the life of the program, can add up; and it increases the size of the executable (byte codes are significantly more compact than expanded JIT code) and this might cause paging, which definitely slows down a program. An alternative approach is lazy evaluation, which means that the code is not JIT compiled until necessary. Thus, code that never gets executed might never get JIT compiled. t Il existe un certain nombre d'autres optimisations possibles dans une JVM. Une d'entre elles, très importante, implique le module de chargement des classes et le compilateur Just-In-Time (JIT). Quand une classe doit être chargée (généralement la première fois que l'on veut créer un objet de cette classe), le fichier .class est trouvé et le byte-code pour cette classe est chargé en mémoire. A ce moment-là, une possibilité est d'utiliser le JIT sur tout le code, mais cela a deux inconvénients. Tout d'abord c'est un peu plus coûteux en temps et, quand on considère toutes les classes chargées sur la durée de vie du programme, cela peut devenir conséquent. De plus, la taille de l'exécutable est augmentée (les byte codes sont bien plus compacts que le code résultant du JIT) et peut donc causer l'utilisation de pages dans la mémoire virtuelle, ce qui ralentit clairement le programme. Une autre approche est l'évaluation paresseuse qui n'utilise le JIT que lorsque cela est nécessaire. Par conséquent, si une partie du code n'est jamais exécutée, il est possible qu'elle ne soit jamais compilée par le JIT.
t t t

Member initialization

t

Initialisation de membre

t t t
Java goes out of its way to guarantee that variables are properly initialized before they are used. In the case of variables that are defined locally to a method, this guarantee comes in the form of a compile-time error. So if you say: t Java prend en charge l'initialisation des variables avant leur utilisation. Dans le cas des variables locales à une méthode, cett garantie prend la forme d'une erreur à la compilation. Donc le code suivant :
t t t
  void f() {
    int i;
    i++;
}
t
void f() {
    int i;
    i++;
  }
t t t
you’ll get an error message that says that i might not have been initialized. Of course, the compiler could have given i a default value, but it’s more likely that this is a programmer error and a default value would have covered that up. Forcing the programmer to provide an initialization value is more likely to catch a bug. t générera un message d'erreur disant que la variable i peut ne pas avoir été initialisée. Bien entendu, le compilateur aurait pu donner à i une valeur par défaut, mais il est plus probable qu'il s'agit d'une erreur de programmation et une valeur par défaut aurait masqué ce problème. En forçant le programmeur à donner une valeur par défaut, il y a plus de chances de repérer un bogue.
t t t
If a primitive is a data member of a class, however, things are a bit different. Since any method can initialize or use that data, it might not be practical to force the user to initialize it to its appropriate value before the data is used. However, it’s unsafe to leave it with a garbage value, so each primitive data member of a class is guaranteed to get an initial value. Those values can be seen here: t Cependant, si une valeur primitive est un membre de données d'une classe, les choses sont un peu différentes. Comme n'importe quelle méthode peut initialiser ou utiliser cette donnée, il ne serait pas très pratique ou faisable de forcer l'utilisateur à l'initialiser correctement avant son utilisation. Cependant, il n'est pas correct de la laisser avec n'importe quoi comme valeur, Java garantit donc de donner une valeur initiale à chaque membre de données avec un type primitif. On peut voir ces valeurs ici :
t t t
//: c04:InitialValues.java
// Shows default initial values.

class Measurement {
  boolean t;
  char c;
  byte b;
  short s;
  int i;
  long l;
  float f;
  double d;
  void print() {
    System.out.println(
      "Data type      Initial value\n" +
      "boolean        " + t + "\n" +
      "char           [" + c + "] "+ (int)c +"\n"+
      "byte           " + b + "\n" +
      "short          " + s + "\n" +
      "int            " + i + "\n" +
      "long           " + l + "\n" +
      "float          " + f + "\n" +
      "double         " + d);
  }
}

public class InitialValues {
  public static void main(String[] args) {
    Measurement d = new Measurement();
    d.print();
    /* In this case you could also say:
    new Measurement().print();
    */
  }
} ///:~
t
//: c04:InitialValues.java
// Imprime les valeurs initiales par défaut.

class Measurement {
  boolean t;
  char c;
  byte b;
  short s;
  int i;
  long l;
  float f;
  double d;
  void print() {
    System.out.println(
      "Data type      Initial value\n" +
      "boolean        " + t + "\n" +
      "char           [" + c + "] "+ (int)c +"\n"+
      "byte           " + b + "\n" +
      "short          " + s + "\n" +
      "int            " + i + "\n" +
      "long           " + l + "\n" +
      "float          " + f + "\n" +
      "double         " + d);
  }
}

public class InitialValues {
  public static void main(String[] args) {
    Measurement d = new Measurement();
    d.print();
    /* Dans ce cas, il est également possible d'écrire :
    new Measurement().print();
    */

  }
} ///:~
t t t
The output of this program is: t Voici la sortie de ce programme :
t t t
Data type      Initial value
boolean        false
char           [ ] 0
byte           0
short          0
int            0
long           0
float          0.0
double 0.0
t
Data type      Initial value
boolean        false
char           [ ] 0
byte           0
short          0
int            0
long           0
float          0.0
double         0.0
t t t
The char value is a zero, which prints as a space. t La valeur pour char est zéro, ce qui se traduit par un espace dans la sortie-écran.
t t t
You’ll see later that when you define an object reference inside a class without initializing it to a new object, that reference is given a special value of null (which is a Java keyword). t Nous verrons plus tard que quand on définit une référence sur un objet dans une classe sans l'initialiser avec un nouvel objet, la valeur spéciale null (mot-clé Java) est donnée à cette référence.
t t t
You can see that even though the values are not specified, they automatically get initialized. So at least there’s no threat of working with uninitialized variables. t On peut voir que même si des valeurs ne sont pas spécifiées, les données sont initialisées automatiquement. Il n'y a donc pas de risque de travailler par inattention avec des variables non-initialisées.
t t t

Specifying initialization

t

Spécifier une initialisation

t t t
What happens if you want to give a variable an initial value? One direct way to do this is simply to assign the value at the point you define the variable in the class. (Notice you cannot do this in C++, although C++ novices always try.) Here the field definitions in class Measurement are changed to provide initial values: t Comment peut-on donner une valeur initiale à une variable ? Une manière directe de le faire est la simple affectation au moment de la définition de la variable dans la classe (note : il n'est pas possible de le faire en C++ bien que tous les débutants s'y essayent). Les définitions des champs de la classe Measurement sont modifiées ici pour fournir des valeurs initiales :
t t t
class Measurement {
  boolean b = true;
  char c = 'x';
  byte B = 47;
  short s = 0xff;
  int i = 999;
  long l = 1;
  float f = 3.14f;
  double d = 3.14159;
//. . .
t
class Measurement {
  boolean b = true;
  char c = 'x';
  byte B = 47;
  short s = 0xff;
  int i = 999;
  long l = 1;
  float f = 3.14f;
  double d = 3.14159;
  //. . .
t t t
You can also initialize nonprimitive objects in this same way. If Depth is a class, you can insert a variable and initialize it like so: t On peut initialiser des objets de type non-primitif de la même manière. Si Depth (NDT : « profondeur ») est une classe, on peut ajouter une variable et l'initialiser de cette façon :
t t t
class Measurement {
  Depth o = new Depth();
  boolean b = true;
// . . .
t
class Measurement {
  Depth o = new Depth();
  boolean b = true;
  // . . .
t t t
If you haven’t given o an initial value and you try to use it anyway, you’ll get a run-time error called an exception (covered in Chapter 10). t Si o ne reçoit pas de valeur initiale et que l'on essaye de l'utiliser malgré tout, on obtient une erreur à l'exécution appelée exception (explications au chapitre 10).
t t t
You can even call a method to provide an initialization value: t Il est même possible d'appeler une méthode pour fournir une valeur d'initialisation :
t t t
class CInit {
  int i = f();
  //...
}
t
class CInit {
  int i = f();
  //...
}
t t t
This method can have arguments, of course, but those arguments cannot be other class members that haven’t been initialized yet. Thus, you can do this: t Bien sûr cette méthode peut avoir des arguments, mais ceux-ci ne peuvent pas être d'autres membres non encore initialisés, de la classe. Par conséquent ce code est valide :
t t t
class CInit {
  int i = f();
  int j = g(i);
  //...
}
t
class CInit {
  int i = f();
  int j = g(i);
  //...
}
t t t
But you cannot do this: t Mais pas celui-ci :
t t t
class CInit {
  int j = g(i);
  int i = f();
  //...
}
t
class CInit {
  int j = g(i);
  int i = f();
  //...
}
t t t
This is one place in which the compiler, appropriately, does complain about forward referencing, since this has to do with the order of initialization and not the way the program is compiled. t C'est un des endroits où le compilateur se plaint avec raison du forward referencing (référence à un objet déclaré plus loin dans le code), car il s'agit d'une question d'ordre d'initialisation et non pas de la façon dont le programme est compilé.
t t t
This approach to initialization is simple and straightforward. It has the limitation that every object of type Measurement will get these same initialization values. Sometimes this is exactly what you need, but at other times you need more flexibility. t Cette approche par rapport à l'initialisation est très simple. Elle est également limitée dans le sens où chaque objet de type Measurement aura les mêmes valeurs d'initialisation. Quelquefois c'est exactement ce dont on a besoin, mais d'autres fois un peu plus de flexibilité serait nécessaire.
t t t

Constructor initialization

t

Initialisation par constructeur

t t t
The constructor can be used to perform initialization, and this gives you greater flexibility in your programming since you can call methods and perform actions at run-time to determine the initial values. There’s one thing to keep in mind, however: you aren’t precluding the automatic initialization, which happens before the constructor is entered. So, for example, if you say: t On peut utiliser le constructeur pour effectuer les initialisations. Cela apporte plus de flexibilité pour le programmeur car il est possible d'appeler des méthodes et effectuer des actions à l'exécution pour déterminer les valeurs initiales. Cependant il y a une chose à se rappeler : cela ne remplace pas l'initialisation automatique qui est faite avant l'exécution du constructeur. Donc par exemple :
t t t
class Counter {
  int i;
  Counter() { i = 7; }
// . . .
t
class Counter {
  int i;
  Counter() { i = 7; }
  // . . .
t t t
then i will first be initialized to 0, then to 7. This is true with all the primitive types and with object references, including those that are given explicit initialization at the point of definition. For this reason, the compiler doesn’t try to force you to initialize elements in the constructor at any particular place, or before they are used—initialization is already guaranteed[30]. t Dans ce cas, i sera d'abord initialisé à 0 puis à 7. C'est ce qui ce passe pour tous les types primitifs et les références sur objet, même pour ceux qui ont été initialisés explicitement au moment de leur définition. Pour cette raison, le compilateur ne force pas l'utilisateur à initialiser les éléments dans le constructeur à un endroit donné, ni avant leur utilisation : l'initialisation est toujours garantie [30].
t t t

Order of initialization

t

Ordre d'initialisation

t t t
Within a class, the order of initialization is determined by the order that the variables are defined within the class. The variable definitions may be scattered throughout and in between method definitions, but the variables are initialized before any methods can be called—even the constructor. For example: t Dans une classe, l'ordre d'initialisation est déterminé par l'ordre dans lequel les variables sont definies. Les définitions de variables peuvent être disséminées n'importe où et même entre les définitions des méthodes, mais elles sont initialisées avant tout appel à une méthode, même le constructeur. Par exemple :
t t t
//: c04:OrderOfInitialization.java
// Demonstrates initialization order.

// When the constructor is called to create a
// Tag object, you'll see a message:
class Tag {
  Tag(int marker) {
    System.out.println("Tag(" + marker + ")");
  }
}

class Card {
  Tag t1 = new Tag(1); // Before constructor
  Card() {
    // Indicate we're in the constructor:
    System.out.println("Card()");
    t3 = new Tag(33); // Reinitialize t3
  }
  Tag t2 = new Tag(2); // After constructor
  void f() {
    System.out.println("f()");
  }
  Tag t3 = new Tag(3); // At end
}

public class OrderOfInitialization {
  public static void main(String[] args) {
    Card t = new Card();
    t.f(); // Shows that construction is done
  }
} ///:~
t
//: c04:OrderOfInitialization.java
// Montre l'ordre d'initialisation.

// Quand le constructeur est appelé pour créer
// un objet Tag, un message s'affichera :
class Tag {
  Tag(int marker) {
    System.out.println("Tag(" + marker + ")");
  }
}

class Card {
  Tag t1 = new Tag(1); // Avant le constructeur
  Card() {
    // Montre que l'on est dans le constructeur :
    System.out.println("Card()");
    t3 = new Tag(33); // Réinitialisation de t3
  }
  Tag t2 = new Tag(2); // Après le constructeur
  void f() {
    System.out.println("f()");
  }
  Tag t3 = new Tag(3); // la fin
}

public class OrderOfInitialization {
  public static void main(String[] args) {
    Card t = new Card();
    t.f(); // Montre que la construction a été effectuée
  }
} ///:~
t t t
In Card, the definitions of the Tag objects are intentionally scattered about to prove that they’ll all get initialized before the constructor is entered or anything else can happen. In addition, t3 is reinitialized inside the constructor. The output is: t Dans la classe Card, les définitions des objets Tag sont intentionnellement dispersées pour prouver que ces objets seront tous initialisés avant toute action (y compris l'appel du constructeur). De plus, t3 est réinitialisé dans le constructeur. La sortie-écran est la suivante :
t t t
Tag(1)
Tag(2)
Tag(3)
Card()
Tag(33)
f()
t
Tag(1)
Tag(2)
Tag(3)
Card()
Tag(33)
f()
t t t
Thus, the t3 reference gets initialized twice, once before and once during the constructor call. (The first object is dropped, so it can be garbage-collected later.) This might not seem efficient at first, but it guarantees proper initialization—what would happen if an overloaded constructor were defined that did not initialize t3 and there wasn’t a “default” initialization for t3 in its definition? t La référence sur t3 est donc initialisée deux fois, une fois avant et une fois pendant l'appel au constructeur (on jette le premier objet pour qu'il soit récupéré par le ramasse-miettes plus tard). A première vue, cela ne semble pas très efficace, mais cela garantit une initialisation correcte ; que se passerait-il si l'on surchargeait le constructeur avec un autre constructeur qui n'initialiserait pas t3 et qu'il n'y avait pas d'initialisation « par défaut » dans la définition de t3 ?
t t t

Static data initialization

t

Initialisation de données statiques

t t t
When the data is static the same thing happens; if it’s a primitive and you don’t initialize it, it gets the standard primitive initial values. If it’s a reference to an object, it’s null unless you create a new object and attach your reference to it. t Quand les données sont statiques (static) la même chose se passe ; s'il s'agit d'une donnée de type primitif et qu'elle n'est pas initialisée, la variable reçoit une valeur initiale standard. Si c'est une référence sur un objet, c'est la valeur null qui est utilisée à moins qu'un nouvel objet ne soit créé et sa référence donnée comme valeur à la variable.
t t t
If you want to place initialization at the point of definition, it looks the same as for non-statics. There’s only a single piece of storage for a static, regardless of how many objects are created. But the question arises of when the static storage gets initialized. An example makes this question clear: t Pour une initialisation à l'endroit de la définition, les mêmes règles que pour les variables non-statiques sont appliquées. Il n'y a qu'une seule version (une seule zone mémoire) pour une variable statique quel que soit le nombre d'objets créés. Mais une question se pose lorsque cette zone statique est initialisée. Un exemple va rendre cette question claire :
t t t
//: c04:StaticInitialization.java
// Specifying initial values in a
// class definition.

class Bowl {
  Bowl(int marker) {
    System.out.println("Bowl(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

class Table {
  static Bowl b1 = new Bowl(1);
  Table() {
    System.out.println("Table()");
    b2.f(1);
  }
  void f2(int marker) {
    System.out.println("f2(" + marker + ")");
  }
  static Bowl b2 = new Bowl(2);
}

class Cupboard {
  Bowl b3 = new Bowl(3);
  static Bowl b4 = new Bowl(4);
  Cupboard() {
    System.out.println("Cupboard()");
    b4.f(2);
  }
  void f3(int marker) {
    System.out.println("f3(" + marker + ")");
  }
  static Bowl b5 = new Bowl(5);
}

public class StaticInitialization {
  public static void main(String[] args) {
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    t2.f2(1);
    t3.f3(1);
  }
  static Table t2 = new Table();
  static Cupboard t3 = new Cupboard();
} ///:~
t
//: c04:StaticInitialization.java
// Préciser des valeurs initiales dans une
// définition de classe.

class Bowl {
  Bowl(int marker) {
    System.out.println("Bowl(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

class Table {
  static Bowl b1 = new Bowl(1);
  Table() {
    System.out.println("Table()");
    b2.f(1);
  }
  void f2(int marker) {
    System.out.println("f2(" + marker + ")");
  }
  static Bowl b2 = new Bowl(2);
}

class Cupboard {
  Bowl b3 = new Bowl(3);
  static Bowl b4 = new Bowl(4);
  Cupboard() {
    System.out.println("Cupboard()");
    b4.f(2);
  }
  void f3(int marker) {
    System.out.println("f3(" + marker + ")");
  }
  static Bowl b5 = new Bowl(5);
}

public class StaticInitialization {
  public static void main(String[] args) {
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    System.out.println(
      "Creating new Cupboard() in main");
    new Cupboard();
    t2.f2(1);
    t3.f3(1);
  }
  static Table t2 = new Table();
  static Cupboard t3 = new Cupboard();
} ///:~
t t t
Bowl allows you to view the creation of a class, and Table and Cupboard create static members of Bowl scattered through their class definitions. Note that Cupboard creates a non-static Bowl b3 prior to the static definitions. The output shows what happens: t Bowl permet de visionner la création d'une classe. Table, ainsi que Cupboard, créent des membres static de Bowl partout au travers de leur définition de classe. Il est à noter que Cupboard crée un Bowl b3 non-statique avant les définitions statiques. La sortie montre ce qui se passe :
t t t
Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
f2(1)
f3(1)
t
Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f(2)
f2(1)
f3(1)
t t t
The static initialization occurs only if it’s necessary. If you don’t create a Table object and you never refer to Table.b1 or Table.b2, the static Bowl b1 and b2 will never be created. However, they are initialized only when the first Table object is created (or the first static access occurs). After that, the static objects are not reinitialized. t L'initialisation statique intervient seulement si c'est nécessaire. Si on ne crée jamais d'objets Table et que Table.b1 ou Table.b2 ne sont jamais référencés, les membres statiques Bowl b1 et b2 ne seront jamais créés. Cependant, ils ne sont initialisés que lorsque le premier objet Table est créé (ou le premier accès statique est effectué). Après cela, les objets statiques ne sont pas réinitialisés.
t t t
The order of initialization is statics first, if they haven’t already been initialized by a previous object creation, and then the non-static objects. You can see the evidence of this in the output. t Dans l'ordre d'initialisation, les membres static viennent en premier, s'ils n'avaient pas déjà été initialisés par une précédente création d'objet, les objets non static sont traités. On peut le voir clairement dans la sortie du programme.
t t t
It’s helpful to summarize the process of creating an object. Consider a class called Dog: t Il peut être utile de résumer le processus de création d'un objet. Considérons une classe appelée Dog :
t t t
  1. The first time an object of type Dog is created, or the first time a static method or static field of class Dog is accessed, the Java interpreter must locate Dog.class, which it does by searching through the classpath.
  2. As Dog.class is loaded (creating a Class object, which you’ll learn about later), all of its static initializers are run. Thus, static initialization takes place only once, as the Class object is loaded for the first time.
  3. When you create a new Dog( ), the construction process for a Dog object first allocates enough storage for a Dog object on the heap.
  4. This storage is wiped to zero, automatically setting all the primitives in that Dog object to their default values (zero for numbers and the equivalent for boolean and char) and the references to null.
  5. Any initializations that occur at the point of field definition are executed.
  6. Constructors are executed. As you shall see in Chapter 6, this might actually involve a fair amount of activity, especially when inheritance is involved.
t
  1. La première fois qu'un objet de type Dog est créé, ou la première fois qu'on utilise une méthode déclarée static ou un champ static de la classe Dog, l'interprèteur Java doit localiser Dog.class, ce qu'il fait en cherchant dans le classpath ;
  2. Au moment où Dog.class est chargée (créant un objet Class, que nous verrons plus tard), toutes les fonctions d'initialisation statiques sont exécutées. Par conséquent, l'initialisation statique n'arrive qu'une fois, au premier chargement de l'objet Class ;
  3. Lorsque l'on exécute new Dog( ) pour créer un nouvel objet de type Dog, le processus de construction commence par allouer suffisamment d'espace mémoire sur le tas pour contenir un objet Dog ;
  4. Cet espace est mis à zéro, donnant automatiquement à tous les membres de type primitif dans cet objet Dog leurs valeurs par défaut (zéro pour les nombres et l'équivalent pour les boolean et les char) et aux références la valeur null ;
  5. Toute initialisation effectuée au moment de la définition des champs est exécutée ;
  6. Les constructeurs sont exécutés. Comme nous le verrons au chapitre 6, ceci peut en fait déclencher beaucoup d'activité, surtout lorsqu'il y a de l'héritage.
t t t

Explicit static initialization

t

Initialisation statique explicite

t t t
Java allows you to group other static initializations inside a special “static construction clause” (sometimes called a static block) in a class. It looks like this: t Java permet au programmeur de grouper toute autre initialisation statique dans une « clause de construction » static (quelquefois appelé bloc statique) dans une classe. Cela ressemble à ceci :
t t t
class Spoon {
  static int i;
  static {
    i = 47;
  }
// . . .
t
class Spoon {
  static int i;
  static {
    i = 47;
  }
  // . . .
t t t
It appears to be a method, but it’s just the static keyword followed by a method body. This code, like other static initializations, is executed only once, the first time you make an object of that class or the first time you access a static member of that class (even if you never make an object of that class). For example: t On dirait une méthode, mais il s'agit simplement du mot-clé static suivi d'un corps de méthode. Ce code, comme les autres initialisations statiques, est exécuté une seule fois, à la création du premier objet de cette classe ou au premier accès à un membre déclaré static de cette classe (même si on ne crée jamais d'objet de cette classe). Par exemple :
t t t
//: c04:ExplicitStatic.java
// Explicit static initialization
// with the "static" clause.

class Cup {
  Cup(int marker) {
    System.out.println("Cup(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

class Cups {
  static Cup c1;
  static Cup c2;
  static {
    c1 = new Cup(1);
    c2 = new Cup(2);
  }
  Cups() {
    System.out.println("Cups()");
  }
}

public class ExplicitStatic {
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Cups.c1.f(99);  // (1)
  }
  // static Cups x = new Cups();  // (2)
  // static Cups y = new Cups();  // (2)
} ///:~
t
//: c04:ExplicitStatic.java
// Initialisation statique explicite
// avec l'instruction "static".

class Cup {
  Cup(int marker) {
    System.out.println("Cup(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

class Cups {
  static Cup c1;
  static Cup c2;
  static {
    c1 = new Cup(1);
    c2 = new Cup(2);
  }
  Cups() {
    System.out.println("Cups()");
  }
}

public class ExplicitStatic {
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Cups.c1.f(99);  // (1)
  }
  // static Cups x = new Cups();  // (2)
  // static Cups y = new Cups();  // (2)
} ///:~
t t t
The static initializers for Cups run when either the access of the static object c1 occurs on the line marked (1), or if line (1) is commented out and the lines marked (2) are uncommented. If both (1) and (2) are commented out, the static initialization for Cups never occurs. Also, it doesn’t matter if one or both of the lines marked (2) are uncommented; the static initialization only occurs once. t Les instructions statiques d'initialisation pour Cups sont exécutées soit quand l'accès à l'objet static c1 intervient à la ligne (1), soit si la ligne (1) est mise en commentaire et les lignes (2) ne le sont pas. Si (1) et (2) sont en commentaire, l'initialisation static pour Cups n'intervient jamais. De plus, que l'on enlève les commentaires pour les deux lignes (2) ou pour une seule n'a aucune importance : l'initialisation statique n'est effectuée qu'une seule fois.
t t t

Non-static instance initialization

t

Initialisation d'instance non statique

t t t
Java provides a similar syntax for initializing non-static variables for each object. Here’s an example: t Java offre une syntaxe similaire pour initialiser les variables non static pour chaque objet. Voici un exemple :
t t t
//: c04:Mugs.java
// Java "Instance Initialization."

class Mug {
  Mug(int marker) {
    System.out.println("Mug(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

public class Mugs {
  Mug c1;
  Mug c2;
  {
    c1 = new Mug(1);
    c2 = new Mug(2);
    System.out.println("c1 & c2 initialized");
  }
  Mugs() {
    System.out.println("Mugs()");
  }
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Mugs x = new Mugs();
  }
} ///:~
t
//: c04:Mugs.java
// Java "Instance Initialization." (Initialisation d'instance de Java)

class Mug {
  Mug(int marker) {
    System.out.println("Mug(" + marker + ")");
  }
  void f(int marker) {
    System.out.println("f(" + marker + ")");
  }
}

public class Mugs {
  Mug c1;
  Mug c2;
  {
    c1 = new Mug(1);
    c2 = new Mug(2);
    System.out.println("c1 & c2 initialized");
  }
  Mugs() {
    System.out.println("Mugs()");
  }
  public static void main(String[] args) {
    System.out.println("Inside main()");
    Mugs x = new Mugs();
  }
} ///:~
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel