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
What happens if your argument is bigger than the argument expected by the overloaded method? A modification of the above program gives the answer: t Qu'arrive-t'il lorsque le paramètre est plus grand que celui attendu par la méthode surchargée ? Une modification du programme précédent donne la réponse :
t t t
//: c04:Demotion.java
// Demotion of primitives and overloading.

public class Demotion {
  static void prt(String s) {
    System.out.println(s);
  }

  void f1(char x) { prt("f1(char)"); }
  void f1(byte x) { prt("f1(byte)"); }
  void f1(short x) { prt("f1(short)"); }
  void f1(int x) { prt("f1(int)"); }
  void f1(long x) { prt("f1(long)"); }
  void f1(float x) { prt("f1(float)"); }
  void f1(double x) { prt("f1(double)"); }

  void f2(char x) { prt("f2(char)"); }
  void f2(byte x) { prt("f2(byte)"); }
  void f2(short x) { prt("f2(short)"); }
  void f2(int x) { prt("f2(int)"); }
  void f2(long x) { prt("f2(long)"); }
  void f2(float x) { prt("f2(float)"); }

  void f3(char x) { prt("f3(char)"); }
  void f3(byte x) { prt("f3(byte)"); }
  void f3(short x) { prt("f3(short)"); }
  void f3(int x) { prt("f3(int)"); }
  void f3(long x) { prt("f3(long)"); }

  void f4(char x) { prt("f4(char)"); }
  void f4(byte x) { prt("f4(byte)"); }
  void f4(short x) { prt("f4(short)"); }
  void f4(int x) { prt("f4(int)"); }

  void f5(char x) { prt("f5(char)"); }
  void f5(byte x) { prt("f5(byte)"); }
  void f5(short x) { prt("f5(short)"); }

  void f6(char x) { prt("f6(char)"); }
  void f6(byte x) { prt("f6(byte)"); }

  void f7(char x) { prt("f7(char)"); }

  void testDouble() {
    double x = 0;
    prt("double argument:");
    f1(x);f2((float)x);f3((long)x);f4((int)x);
    f5((short)x);f6((byte)x);f7((char)x);
  }
  public static void main(String[] args) {
    Demotion p = new Demotion();
    p.testDouble();
  }
} ///:~
t
//: c04:Demotion.java
// Types de base déchus et surcharge.

public class Demotion {
  static void prt(String s) {
    System.out.println(s);
  }

  void f1(char x) { prt("f1(char)"); }
  void f1(byte x) { prt("f1(byte)"); }
  void f1(short x) { prt("f1(short)"); }
  void f1(int x) { prt("f1(int)"); }
  void f1(long x) { prt("f1(long)"); }
  void f1(float x) { prt("f1(float)"); }
  void f1(double x) { prt("f1(double)"); }

  void f2(char x) { prt("f2(char)"); }
  void f2(byte x) { prt("f2(byte)"); }
  void f2(short x) { prt("f2(short)"); }
  void f2(int x) { prt("f2(int)"); }
  void f2(long x) { prt("f2(long)"); }
  void f2(float x) { prt("f2(float)"); }

  void f3(char x) { prt("f3(char)"); }
  void f3(byte x) { prt("f3(byte)"); }
  void f3(short x) { prt("f3(short)"); }
  void f3(int x) { prt("f3(int)"); }
  void f3(long x) { prt("f3(long)"); }

  void f4(char x) { prt("f4(char)"); }
  void f4(byte x) { prt("f4(byte)"); }
  void f4(short x) { prt("f4(short)"); }
  void f4(int x) { prt("f4(int)"); }

  void f5(char x) { prt("f5(char)"); }
  void f5(byte x) { prt("f5(byte)"); }
  void f5(short x) { prt("f5(short)"); }

  void f6(char x) { prt("f6(char)"); }
  void f6(byte x) { prt("f6(byte)"); }

  void f7(char x) { prt("f7(char)"); }

  void testDouble() {
    double x = 0;
    prt("double argument:");
    f1(x);f2((float)x);f3((long)x);f4((int)x);
    f5((short)x);f6((byte)x);f7((char)x);
  }
  public static void main(String[] args) {
    Demotion p = new Demotion();
    p.testDouble();
  }
} ///:~
t t t
Here, the methods take narrower primitive values. If your argument is wider then you must cast to the necessary type using the type name in parentheses. If you don’t do this, the compiler will issue an error message. t Ici, les méthodes prennent des types de base plus restreints. Si les paramètres sont d'un type plus grand, if faut les caster (convertir) vers le type requis en utilisant le nom du type entre parenthèses. Sinon, le compilateur donnera un message d'erreur.
t t t
You should be aware that this is a narrowing conversion, which means you might lose information during the cast. This is why the compiler forces you to do it—to flag the narrowing conversion. t Il est important de noter qu'il s'agit d'une conversion vers un type plus petit, ce qui signifie que des informations peuvent être perdues pendant la conversion. C'est d'ailleurs pour cette raison que le compilateur force une conversion explicite.
t t t

Overloading on return values

t

Surcharge sur la valeur de retour

t t t
It is common to wonder “Why only class names and method argument lists? Why not distinguish between methods based on their return values?” For example, these two methods, which have the same name and arguments, are easily distinguished from each other: t Il est fréquent de se demander «Pourquoi seulement les noms de classes et la liste des paramètres des méthodes ? Pourquoi ne pas aussi distinguer entre deux méthodes en se basant sur leur type de retour ?» Par exemple, ces deux méthodes, qui ont le même nom et les mêmes arguments, peuvent facilement être distinguées l'une de l'autre :
t t t
void f() {}
int f() {}
t
void f() {}
int f() {}
t t t
This works fine when the compiler can unequivocally determine the meaning from the context, as in int x = f( ). However, you can call a method and ignore the return value; this is often referred to as calling a method for its side effect since you don’t care about the return value but instead want the other effects of the method call. So if you call the method this way: t Cela fonctionne bien lorsque le compilateur peut déterminer le sens sans équivoque depuis le contexte, comme dans int x = f( ). Par contre, on peut utiliser une méthode et ignorer sa valeur de retour. On se réfère souvent à cette action comme appeler une méthode pour ses effets de bord puisqu'on ne s'intéresse pas à la valeur de retour mais aux autres effets que cet appel de méthode génère. Donc, si on appelle la méthode comme suit :
t t t
f();
t
f();
t t t
how can Java determine which
f( ) should be called? And how could someone reading the code see
it? Because of this sort of problem, you cannot use return value types to
distinguish overloaded
methods.
t Comment Java peut-il déterminer quelle méthode f( ) doit être exécutée ? Et comment quelqu'un lisant ce code pourrait-il le savoir ? A cause de ce genre de difficultés, il est impossible d'utiliser la valeur de retour pour différencier deux méthodes Java surchargées.
t t t


Default constructors


t

Constructeurs par défaut

t t t
As mentioned previously, a default
constructor (a.k.a. a “no-arg” constructor)
is one without arguments, used to
create a “vanilla object.” If you create a class that has no
constructors, the compiler will automatically create a default constructor for
you. For example:

t Comme mentionné précédemment, un constructeur par défaut (c.a.d un constructeur «no-arg» ) est un constructeur sans argument, utilisé pour créer des « objets de base ». Si une classe est créée sans constructeur, le compilateur créé automatiquement un constructeur par défaut. Par exemple :
t t t
//: c04:DefaultConstructor.java

class Bird {
  int i;
}

public class DefaultConstructor {
  public static void main(String[] args) {
    Bird nc = new Bird(); // default!
  }
} ///:~
t
//: c04:DefaultConstructor.java

class Bird {
  int i;
}

public class DefaultConstructor {
  public static void main(String[] args) {
    Bird nc = new Bird(); // défaut !
  }
} ///:~
t t t
The line t La ligne
t t t
new Bird();
t
new Bird();
t t t
creates a new object and calls the
default constructor, even though one was not explicitly defined. Without it we
would have no method to call to build our object. However, if you define any
constructors (with or without arguments), the compiler will not
synthesize one for you:

t crée un nouvel objet et appelle le constructeur par défaut, même s'il n'était pas défini explicitement. Sans lui, il n'y aurait pas de méthode à appeler pour créer cet objet. Par contre, si au moins un constructeur est défini (avec ou sans argument), le compilateur n'en synthétisera pas un :
t t t
class Bush {
  Bush(int i) {}
  Bush(double d) {}
}
t
class Bush {
  Bush(int i) {}
  Bush(double d) {}
}
t t t
Now if you say: t Maintenant si on écrit :
t t t
new Bush();
t
new Bush();
t t t
the compiler will complain that it cannot
find a constructor that matches. It’s as if when you don’t put in
any constructors, the compiler says “You are bound to need some
constructor, so let me make one for you.” But if you write a constructor,
the compiler says “You’ve written a constructor so you know what
you’re doing; if you didn’t put in a default it’s because you
meant to leave it
out.”
t le compilateur donnera une erreur indiquant qu'aucun constructeur ne correspond. C'est comme si lorsqu'aucun constructeur n'est fourni, le compilateur dit «Il faut un constructeur, je vais en créer un.» Alors que s'il existe un constructeur, le compilateur dit «Il y a un constructeur donc le développeur sait se qu'il fait; s'il n'a pas défini de constructeur par défaut c'est qu'il ne désirait pas qu'il y en ait un.»
t t t


The this keyword


t

Le mot-clé this

t t t
If you have two objects of the same type
called a and b, you might wonder how it is that you can call a
method f( ) for both those objects:

t Lorsqu'il existe deux objets a et b du même type , il est intéressant de se demander comment on peut appeler une méthode f( ) sur ces deux objets :
t t t
class Banana { void f(int i) { /* ... */ } }
Banana a = new Banana(), b = new Banana();
a.f(1);
b.f(2);
t
class Banana { void f(int i) { /* ... */ } }
Banana a = new Banana(), b = new Banana();
a.f(1);
b.f(2);
t t t
If there’s only one method called f( ), how can that method know whether it’s being called for the object a or b? t S'il y a une unique méthode f( ), comment cette méthode peut-elle savoir si elle a été appelée sur l'objet a ou b ?
t t t
To allow you to write the code in a convenient object-oriented syntax in which you “send a message to an object,” the compiler does some undercover work for you. There’s a secret first argument passed to the method f( ), and that argument is the reference to the object that’s being manipulated. So the two method calls above become something like: t Pour permettre au développeur d'écrire le code dans une syntaxe pratique et orienté objet dans laquelle on «envoie un message vers un objet,» le compilateur effectue un travail secret pour le développeur. Il y a un premier paramètre caché passé à la méthode f( ), et ce paramètre est une référence vers l'objet en train d'être manipulé. Les deux appels de méthode précédents correspondent donc à ceci :
t t t
Banana.f(a,1);
Banana.f(b,2);
t
Banana.f(a,1);
Banana.f(b,2);
t t t
This is internal and you can’t write these expressions and get the compiler to accept them, but it gives you an idea of what’s happening. t Ce travail est interne et il est impossible d'écrire des expressions de ce type directement en espérant que le compilateur les acceptera, mais cela donne une idée de ce qui se passe.
t t t
Suppose you’re inside a method and you’d like to get the reference to the current object. Since that reference is passed secretly by the compiler, there’s no identifier for it. However, for this purpose there’s a keyword: this. The this keyword—which can be used only inside a method—produces the reference to the object the method has been called for. You can treat this reference just like any other object reference. Keep in mind that if you’re calling a method of your class from within another method of your class, you don’t need to use this; you simply call the method. The current this reference is automatically used for the other method. Thus you can say: t Supposons maintenant que l'on est à l'intérieur d'une méthode et que l'on désire obtenir une référence sur l'objet courant. Comme cette référence est passée en tant que paramètre caché par le compilateur, il n'y a pas d'identificateur pour elle. Cette pour cette raison que le mot clé this existe. this - qui ne peut être utilisé qu'à l'intérieur d'une méthode - est une référence sur l'objet pour lequel cette méthode à été appelée. On peut utiliser cette référence comme tout autre référence vers un objet. Il n'est toutefois pas nécessaire d'utiliser this pour appeler une méthode de la classe courante depuis une autre méthode de la classe courante ; il suffit d'appeler cette méthode. La référence this est automatiquement utilisée pour l'autre méthode. On peut écrire :
t t t
class Apricot {
  void pick() { /* ... */ }
  void pit() { pick(); /* ... */ }
}
t
class Apricot {
  void pick() { /* ... */ }
  void pit() { pick(); /* ... */ }
}
t t t
Inside pit( ), you could say this.pick( ) but there’s no need to. The compiler does it for you automatically. The this keyword is used only for those special cases in which you need to explicitly use the reference to the current object. For example, it’s often used in return statements when you want to return the reference to the current object: t A l'intérieur de pit( ), on pourrait écrire this.pick( ) mais ce n'est pas nécessaire. Le compilateur le fait automatiquement pour le développeur. Le mot-clé this est uniquement utilisé pour les cas spéciaux dans lesquels on doit utiliser explicitement une référence sur l'objet courant. Par exemple, il est courament utilisé en association avec return quand on désire renvoyer une référence sur l'objet courant :
t t t
//: c04:Leaf.java
// Simple use of the "this" keyword.

public class Leaf {
  int i = 0;
  Leaf increment() {
    i++;
    return this;
  }
  void print() {
    System.out.println("i = " + i);
  }
  public static void main(String[] args) {
    Leaf x = new Leaf();
    x.increment().increment().increment().print();
  }
} ///:~
t
//: c04:Leaf.java
// Utilisation simple du mot-clé "this".

public class Leaf {
  int i = 0;
  Leaf increment() {
    i++;
    return this;
  }
  void print() {
    System.out.println("i = " + i);
  }
  public static void main(String[] args) {
    Leaf x = new Leaf();
    x.increment().increment().increment().print();
  }
} ///:~
t t t
Because increment( ) returns the reference to the current object via the this keyword, multiple operations can easily be performed on the same object. t Puisque increment( ) renvoie une référence vers l'objet courant par le biais du mot-clé this, on peut facilement appeler plusieurs opérations successivement sur le même objet.
t t t

Calling constructors from constructors

t

Appeler un constructeur depuis un autre constructeur

t t t
When you write several constructors for a class, there are times when you’d like to call one constructor from another to avoid duplicating code. You can do this using the this keyword. t Quand une classe possède plusieurs constructeurs, il peut être utile d'appeler un constructeur depuis un autre pour éviter de la duplication de code. C'est possible grâce au mot-clé this.
t t t
Normally, when you say this, it is in the sense of “this object” or “the current object,” and by itself it produces the reference to the current object. In a constructor, the this keyword takes on a different meaning when you give it an argument list: it makes an explicit call to the constructor that matches that argument list. Thus you have a straightforward way to call other constructors: t En temps normal, this signifie «cet objet» ou «l'objet courant,» et renvoie une référence sur l'objet courant. Dans un constructeur, le mot-clé this prend un sens différent quand on lui passe une liste de paramètres : il signifie un appel explicite au constructeur qui correspond à cette liste de paramètres. Cela donne un moyen très simple d'appeler d'autres constructeurs :
t t t
//: c04:Flower.java
// Calling constructors with "this."

public class Flower {
  int petalCount = 0;
  String s = new String("null");
  Flower(int petals) {
    petalCount = petals;
    System.out.println(
      "Constructor w/ int arg only, petalCount= "
      + petalCount);
  }
  Flower(String ss) {
    System.out.println(
      "Constructor w/ String arg only, s=" + ss);
    s = ss;
  }
  Flower(String s, int petals) {
    this(petals);
//!    this(s); // Can't call two!
    this.s = s; // Another use of "this"
    System.out.println("String & int args");
  }
  Flower() {
    this("hi", 47);
    System.out.println(
      "default constructor (no args)");
  }
  void print() {
//!    this(11); // Not inside non-constructor!
    System.out.println(
      "petalCount = " + petalCount + " s = "+ s);
  }
  public static void main(String[] args) {
    Flower x = new Flower();
    x.print();
  }
} ///:~
t
//: c04:Flower.java
// Appel de constructeurs avec "this."

public class Flower {
  int petalCount = 0;
  String s = new String("null");
  Flower(int petals) {
    petalCount = petals;
    // Constructeur avec un unique paramètre int
    System.out.println(
      "Constructor w/ int arg only, petalCount= "
      + petalCount);
  }
  Flower(String ss) {
    // Constructeur avec un unique paramètre String
    System.out.println(
      "Constructor w/ String arg only, s=" + ss);
    s = ss;
  }
  Flower(String s, int petals) {
    this(petals);
//!    this(s); // Impossible d'en appeler deux !
    this.s = s; // Autre usage de "this"
    System.out.println("String & int args");
  }

  // Constructeur par défaut
  Flower() {
    this("hi", 47);
    System.out.println(
      "default constructor (no args)");
  }
  void print() {
//!    this(11); // Pas à l'intérieur d'une méthode normale !
    System.out.println(
      "petalCount = " + petalCount + " s = "+ s);
  }
  public static void main(String[] args) {
    Flower x = new Flower();
    x.print();
  }
} ///:~
t t t
The constructor Flower(String s, int petals) shows that, while you can call one constructor using this, you cannot call two. In addition, the constructor call must be the first thing you do or you’ll get a compiler error message. t Le constructeur Flower(String s, int petals) montre qu'on peut appeler un constructeur en utilisant this, mais pas deux. De plus, l'appel au constructeur doit absolument être la première instruction sinon le compilateur donnera un message d'erreur.
t t t
This example also shows another way you’ll see this used. Since the name of the argument s and the name of the member data s are the same, there’s an ambiguity. You can resolve it by saying this.s to refer to the member data. You’ll often see this form used in Java code, and it’s used in numerous places in this book. t Cet exemple montre aussi un usage différent du mot-clé this. Les noms du paramètre s et du membre de données s étant les mêmes, il y a ambiguïtée. On la résoud en utilisant this.s pour se référer au membre de donnés. Cette forme est très courante en Java et utilisée fréquemment dans ce livre.
t t t
In print( ) you can see that the compiler won’t let you call a constructor from inside any method other than a constructor. t Dans la méthode print( ) on peut voir que le compilateur ne permet pas l'appel d'un constructeur depuis toute autre méthode qu'un constructeur.
t t t

The meaning of static

t

La signification de static

t t t
With the this keyword in mind, you can more fully understand what it means to make a method static. It means that there is no this for that particular method. You cannot call non-static methods from inside static methods[28] (although the reverse is possible), and you can call a static method for the class itself, without any object. In fact, that’s primarily what a static method is for. It’s as if you’re creating the equivalent of a global function (from C). Except global functions are not permitted in Java, and putting the static method inside a class allows it access to other static methods and to static fields. t En pensant au mot-clé this, on comprend mieux le sens de rendre une méthode statics. Cela signifie qu'il n'y a pas de this pour cette méthode. Il est impossible d'appeler une méthode non-static depuis une méthode static [28] (par contre, l'inverse est possible), et il est possible d'appeler une méthode static sur la classe elle-même, sans aucun objet. En fait, c'est principalement la raison de l'existence des méthodes static. C'est l'équivalent d'une fonction globale en C. Sauf que les fonctions globales sont interdites en Java, et ajouter une méthode static dans une classe lui permet d'accéder à d'autres méthodes static ainsi qu'aux membres static.
t t t
Some people argue that static methods are not object-oriented since they do have the semantics of a global function; with a static method you don’t send a message to an object, since there’s no this. This is probably a fair argument, and if you find yourself using a lot of static methods you should probably rethink your strategy. However, statics are pragmatic and there are times when you genuinely need them, so whether or not they are “proper OOP” should be left to the theoreticians. Indeed, even Smalltalk has the equivalent in its “class methods.” t Certaines personnes argumentent que les méthodes static ne sont pas orientées objet puisqu'elles ont la sémantique des fonctions globales ; avec une méthode static on n'envoie pas un message vers un objet, puisqu'il n'y a pas de this. C'est probablement un argument valable, et si vous utilisez beaucoup de méthodes statiques vous devriez repenser votre stratégie. Pourtant, les méthodes statics sont utiles et il y a des cas où on en a vraiment besoin. On peut donc laisser les théoriciens décider si oui ou non il s'agit de vraie programmation orientée objet. D'ailleurs, même Smalltalk a un équivalent avec ses «méthodes de classe.»
t t t

Cleanup: finalization and garbage collection

t

Nettoyage : finalisation et ramasse-miettes

t t t
Programmers know about the importance of initialization, but often forget the importance of cleanup. After all, who needs to clean up an int? But with libraries, simply “letting go” of an object once you’re done with it is not always safe. Of course, Java has the garbage collector to reclaim the memory of objects that are no longer used. Now consider a very unusual case. Suppose your object allocates “special” memory without using new. The garbage collector knows only how to release memory allocated with new, so it won’t know how to release the object’s “special” memory. To handle this case, Java provides a method called finalize( ) that you can define for your class. Here’s how it’s supposed to work. When the garbage collector is ready to release the storage used for your object, it will first call finalize( ), and only on the next garbage-collection pass will it reclaim the object’s memory. So if you choose to use finalize( ), it gives you the ability to perform some important cleanup at the time of garbage collection. t Les programmeurs connaissent l'importance de l'initialisation mais oublient souvent celle du nettoyage. Après tout, qui a besoin de nettoyer un int ? Cependant, avec des bibliothèques, simplement oublier un objet après son utilisation n'est pas toujours sûr. Bien entendu, Java a un ramasse-miettes pour récupérer la mémoire prise par des objets qui ne sont plus utilisés. Considérons maintenant un cas très particulier. Supposons que votre objet alloue une zone de mémoire spéciale sans utiliser new. Le ramasse-miettes ne sait récupérer que la mémoire allouée avec new, donc il ne saura pas comment récupérer la zone «speciale» de mémoire utilisée par l'objet. Pour gérer ce cas, Java fournit une méthode appelée finalize( ) qui peut être définie dans votre classe. Voici comment c'est supposé marcher. Quand le ramasse-miettes est prêt à libérer la mémoire utilisée par votre objet, il va d'abord appeler finalize( ) et ce n'est qu'à la prochaine passe du ramasse-miettes que la mémoire de l'objet est libérée. En choisissant d'utiliser finalize( ), on a la possibilité d'effectuer d'importantes tâches de nettoyage à l'exécution du ramasse-miettes.
t t t
This is a potential programming pitfall because some programmers, especially C++ programmers, might initially mistake finalize( ) for the destructor in C++, which is a function that is always called when an object is destroyed. But it is important to distinguish between C++ and Java here, because in C++ objects always get destroyed (in a bug-free program), whereas in Java objects do not always get garbage-collected. Or, put another way: t C'est un piège de programmation parce que certains programmeurs, particulièrement les programmeurs C++, risquent au début de confondre finalize( ) avec le destructeur de C++ qui est une fonction toujours appelée quand un objet est détruit. Cependant il est important ici de faire la différence entre C++ et Java, car en C++ les objets sont toujours détruits (dans un programme sans bug), alors qu'en Java les objets ne sont pas toujours récupérés par le ramasse-miettes. Dit autrement :
t t t
Garbage collection is not destruction. t Le mécanisme de ramasse-miettes n'est pas un mécanisme de destruction.
t t t
If you remember this, you will stay out of trouble. What it means is that if there is some activity that must be performed before you no longer need an object, you must perform that activity yourself. Java has no destructor or similar concept, so you must create an ordinary method to perform this cleanup. For example, suppose in the process of creating your object it draws itself on the screen. If you don’t explicitly erase its image from the screen, it might never get cleaned up. If you put some kind of erasing functionality inside finalize( ), then if an object is garbage-collected, the image will first be removed from the screen, but if it isn’t, the image will remain. So a second point to remember is: t Si vous vous souvenez de cette règle de base, il n'y aura pas de problème. Cela veut dire que si une opération doit être effectuée avant la disparition d'un objet, celle-ci est à la charge du développeur. Java n'a pas de mécanisme équivalent au destructeur, il est donc nécessaire de créer une méthode ordinaire pour réaliser ce nettoyage. Par exemple, supposons qu'un objet se dessine à l'écran pendant sa création. Si son image n'est pas effacée explicitement de l'écran, il se peut qu'elle ne le soit jamais. Si l'on ajoute une fonctionnalité d'effacement dans finalize( ), alors l'image sera effacée de l'écran si l'objet est récupéré par le ramasse-miette, sinon l'image restera. Il y a donc une deuxième règle à se rappeler :
t t t
Your objects might not get garbage-collected. t Les objets peuvent ne pas être récupérés par le ramasse-miettes.
t t t
You might find that the storage for an object never gets released because your program never nears the point of running out of storage. If your program completes and the garbage collector never gets around to releasing the storage for any of your objects, that storage will be returned to the operating system en masse as the program exits. This is a good thing, because garbage collection has some overhead, and if you never do it you never incur that expense. t Il se peut que la mémoire prise par un objet ne soit jamais libérée parce que le programme n'approche jamais la limite de mémoire qui lui a été attribuée. Si le programme se termine sans que le ramasse-miettes n'ait jamais libéré la mémoire prise par les objets, celle-ci sera rendue en masse (NDT : en français dans le texte) au système d'exploitation au moment où le programme s'arrête. C'est une bonne chose, car le ramasse-miettes implique un coùt supplémentaire et s'il n'est jamais appelé, c'est autant d'économisé.
t t t

What is finalize( ) for?

t

A quoi sert finalize( ) ?

t t t
You might believe at this point that you should not use finalize( ) as a general-purpose cleanup method. What good is it? t A ce point, on peut croire qu'il ne faudrait pas utiliser finalize( ) comme méthode générale de nettoyage. A quoi sert-elle alors ?
t t t
A third point to remember is: t Une troisième règle stipule :
t t t
Garbage collection is only about memory. t Le ramasse-miettes ne s'occupe que de la mémoire.
t t t
That is, the sole reason for the existence of the garbage collector is to recover memory that your program is no longer using. So any activity that is associated with garbage collection, most notably your finalize( ) method, must also be only about memory and its deallocation. t C'est à dire que la seule raison d'exister du ramasse-miettes est de récupérer la mémoire que le programme n'utilise plus. Par conséquent, toute activité associée au ramasse-miettes, la méthode finalize( ) en particulier, doit se concentrer sur la mémoire et sa libération.
t t t
Does this mean that if your object contains other objects finalize( ) should explicitly release those objects? Well, no—the garbage collector takes care of the release of all object memory regardless of how the object is created. It turns out that the need for finalize( ) is limited to special cases, in which your object can allocate some storage in some way other than creating an object. But, you might observe, everything in Java is an object so how can this be? t Est-ce que cela veut dire que si un objet contient d'autres objets, finalize( ) doit libérer ces objets explicitement ? La réponse est... non. Le ramasse-miettes prend soin de libérer tous les objets quelle que soit la façon dont ils ont été créés. Il se trouve que l'on a uniquement besoin de finalize( ) dans des cas bien précis où un objet peut allouer de la mémoire sans créer un autre objet. Cependant vous devez vous dire que tout est objet en Java, donc comment est-ce possible ?
t t t
It would seem that finalize( ) is in place because of the possibility that you’ll do something C-like by allocating memory using a mechanism other than the normal one in Java. This can happen primarily through native methods, which are a way to call non-Java code from Java. (Native methods are discussed in Appendix B.) C and C++ are the only languages currently supported by native methods, but since they can call subprograms in other languages, you can effectively call anything. Inside the non-Java code, C’s malloc( ) family of functions might be called to allocate storage, and unless you call free( ) that storage will not be released, causing a memory leak. Of course, free( ) is a C and C++ function, so you’d need to call it in a native method inside your finalize( ). t Il semblerait que finalize( ) ait été introduit parce qu'il est possible d'allouer de la mémoire à-la-C en utilisant un mécanisme autre que celui proposé normalement par Java. Cela arrive généralement avec des méthodes natives, qui sont une façon d'appeler du code non-Java en Java (les méthodes natives sont expliquées en Appendice B). C et C++ sont les seuls langages actuellement supportés par les méthodes natives, mais comme elles peuvent appeler des routines écrites avec d'autres langages, il est en fait possible d'appeler n'importe quoi. Dans ce code non-Java, on peut appeler des fonctions de la famille de malloc( ) en C pour allouer de la mémoire, et à moins qu'un appel à free( ) ne soit effectué cette mémoire ne sera pas libérée, provoquant une «fuite». Bien entendu, free( ) est une fonction C et C++, ce qui veut dire qu'elle doit être appelée dans une méthode native dans le finalize( ) correspondant.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel