t
t
t
t
t t 6) Réutiliser les classes
tttt
6) Réutiliser les classes
Texte original t Traducteur : Olivier THOMANN
t
t
    
Ce chapitre contient 4 pages
1 2 3 4
\\\
t t t
t t t
t
05.07.01 - version 1.2 [Armel] :
- Ajout des tags de séparation des pages.
25.04.2001 - version 1.1 :
- Mise en forme du code html (titres-hx[verdana], paragraphes-p[Georgia], code-blockquote).
Traducteur :
- Olivier THOMANN
Texte original :
-Thinking in Java, 2nd edition, Revision 10
  © 2000 by Bruce Eckel
t t t
6: Reusing Classes t 6 : Réutiliser les classes
t t t
One of the most compelling features about Java is code reuse. But to be revolutionary, you’ve got to be able to do a lot more than copy code and change it. t Une des caractéristiques les plus excitantes de Java est la réutilisation du code. Mais pour être vraiment révolutionnaire, il faut faire plus que copier du code et le changer.
t t t
That’s the approach used in procedural languages like C, and it hasn’t worked very well. Like everything in Java, the solution revolves around the class. You reuse code by creating new classes, but instead of creating them from scratch, you use existing classes that someone has already built and debugged. t C'est l'approche utilisée dans les langages procéduraux comme C, et ça n'a pas très bien fonctionné. Comme tout en Java, la solution réside dans les classes. On réutilise du code en créant de nouvelles classes, mais au lieu de les créer depuis zéro, on utilise les classes que quelqu'un a construit et testé.
t t t
The trick is to use the classes without soiling the existing code. In this chapter you’ll see two ways to accomplish this. The first is quite straightforward: You simply create objects of your existing class inside the new class. This is called composition, because the new class is composed of objects of existing classes. You’re simply reusing the functionality of the code, not its form. t L'astuce est d'utiliser les classes sans détériorer le code existant. Dans ce chapitre nous verrons deux manières de faire. La première est plutôt directe : On crée simplement des objets de nos classes existantes à l'intérieur de la nouvelle classe. Ça s'appelle la composition, parce que la nouvelle classe se compose d'objets de classes existantes. On réutilise simplement les fonctionnalités du code et non sa forme.
t t t
The second approach is more subtle. It creates a new class as a type of an existing class. You literally take the form of the existing class and add code to it without modifying the existing class. This magical act is called inheritance, and the compiler does most of the work. Inheritance is one of the cornerstones of object-oriented programming, and has additional implications that will be explored in Chapter 7. t La seconde approche est plus subtile. On crée une nouvelle classe comme un type d'une classe existante. On prend littéralement la forme d'une classe existante et on lui ajoute du code sans modifier la classe existante. Cette magie s'appelle l'héritage, et le compilateur fait le plus gros du travail. L'héritage est une des pierres angulaires de la programmation par objets, et a bien d'autres implications qui seront explorées au chapitre 7.
t t t
It turns out that much of the syntax and behavior are similar for both composition and inheritance (which makes sense because they are both ways of making new types from existing types). In this chapter, you’ll learn about these code reuse mechanisms. t Il s'avère que beaucoup de la syntaxe et du comportement sont identiques pour la composition et l' héritage (cela se comprend parce qu'ils sont tous deux des moyens de construire des nouveaux types à partir de types existants). Dans ce chapitre, nous apprendrons ces mécanismes de réutilisation de code.
t t t

Composition syntax

t

Syntaxe de composition

t t t
Until now, composition has been used quite frequently. You simply place object references inside new classes. For example, suppose you’d like an object that holds several String objects, a couple of primitives, and an object of another class. For the nonprimitive objects, you put references inside your new class, but you define the primitives directly: t Jusqu'à maintenant, la composition a été utilisée assez fréquemment. On utilise simplement des références sur des objets dans de nouvelles classes. Par exemple, supposons que l'on souhaite un objet qui contient plusieurs objets de type String, quelques types primitifs et un objet d'une autre classe. Pour les objets, on met des références à l'intérieur de notre nouvelle classe, mais on définit directement les types primitifs:
t t t
//: c06:SprinklerSystem.java
// Composition for code reuse.

class WaterSource {
  private String s;
  WaterSource() {
    System.out.println("WaterSource()");
    s = new String("Constructed");
  }
  public String toString() { return s; }
}

public class SprinklerSystem {
  private String valve1, valve2, valve3, valve4;
  WaterSource source;
  int i;
  float f;
  void print() {
    System.out.println("valve1 = " + valve1);
    System.out.println("valve2 = " + valve2);
    System.out.println("valve3 = " + valve3);
    System.out.println("valve4 = " + valve4);
    System.out.println("i = " + i);
    System.out.println("f = " + f);
    System.out.println("source = " + source);
  }
  public static void main(String[] args) {
    SprinklerSystem x = new SprinklerSystem();
    x.print();
  }
} ///:~
t
// ! c06:SprinklerSystem.java
// La composition pour réutiliser du code.

class WaterSource {
  private String s;
  WaterSource() {
    System.out.println("WaterSource()");
    s = new String("Constructed");
  }
  public String toString() { return s; }
}

public class SprinklerSystem {
  private String valve1, valve2, valve3, valve4;
  WaterSource source;
  int i;
  float f;
  void print() {
    System.out.println("valve1 = " + valve1);
    System.out.println("valve2 = " + valve2);
    System.out.println("valve3 = " + valve3);
    System.out.println("valve4 = " + valve4);
    System.out.println("i = " + i);
    System.out.println("f = " + f);
    System.out.println("source = " + source);
  }
  public static void main(String[] args) {
    SprinklerSystem x = new SprinklerSystem();
    x.print();
  }
} ///:~
t t t
One of the methods defined in WaterSource is special: toString( ). You will learn later that every nonprimitive object has a toString( ) method, and it’s called in special situations when the compiler wants a String but it’s got one of these objects. So in the expression: t Une des méthodes définies dans WaterSource est spéciale : toString( ). Vous apprendrez plus tard que chaque type non primitif a une méthode toString( ), et elle est appelée dans des situations spéciales lorsque le compilateur attend une String alors qu'il ne trouve qu'un objet. Donc dans une expression:
t t t
System.out.println("source = " + source);
t
System.out.println("source = " + source);
t t t
the compiler sees you trying to add a
String object ("source = ") to a WaterSource. This
doesn’t make sense to it, because you can only “add” a
String to another String, so it says “I’ll turn
source into a String by calling toString( )!”
After doing this it can combine the two Strings and pass the resulting
String to System.out.println( ). Any time you want to allow
this behavior with a class you create you need only write a
toString( ) method.

t le compilateur voit que vous essayez d'ajouter un objet String ("source = ") à un WaterSource. Ceci n'a pas de sens parce qu'on peut seulement ajouter une String à une autre String, donc il se dit qu'il va convertir source en une String en appelant toString( ) ! Après avoir fait cela il combine les deux Strings et passe la String résultante à System.out.println( ). Dès qu'on veut permettre ce comportement avec une classe qu'on crée, il suffit simplement de définir une méthode toString( ).
t t t
At first glance, you might
assume—Java being as safe and careful as it is—that the compiler
would automatically construct objects for each of the references in the above
code; for example, calling the default constructor for WaterSource to
initialize source. The output of the print statement is in
fact:

t Au premier regard, on pourrait supposer — Java étant sûr et prudent comme il l'est — que le compilateur construirait automatiquement des objets pour chaque référence dans le code ci-dessus ; par exemple, en appelant le constructeur par défaut pour WaterSource pour initialiser source. Le résultat de l'instruction d'impression affiché est en fait : 
t t t
valve1 = null
valve2 = null
valve3 = null
valve4 = null
i = 0
f = 0.0
source = null
t
valve1 = null
valve2 = null
valve3 = null
valve4 = null
i = 0
f = 0.0
source = null
t t t
Primitives that are fields in a class are automatically initialized to zero, as noted in Chapter 2. But the object references are initialized to null, and if you try to call methods for any of them you’ll get an exception. It’s actually pretty good (and useful) that you can still print them out without throwing an exception. t Les types primitifs qui sont des champs d'une classe sont automatiquement initialisés à zéro, comme précisé dans le chapitre 2. Mais les références objet sont initialisées à null, et si on essaye d'appeler des méthodes pour l'un d'entre eux, on obtient une exception. En fait il est bon (et utile) qu'on puisse les afficher sans lancer d'exception.
t t t
It makes sense that the compiler doesn’t just create a default object for every reference because that would incur unnecessary overhead in many cases. If you want the references initialized, you can do it: t On comprend bien que le compilateur ne crée pas un objet par défaut pour chaque référence parce que cela induirait souvent une surcharge inutile. Si on veut initialiser les références, on peut faire :
t t t
  1. At the point the objects are defined. This means that they’ll always be initialized before the constructor is called.
  2. In the constructor for that class.
  3. Right before you actually need to use the object. This is often called lazy initializatio
t
  1. Au moment où les objets sont définis. Cela signifie qu'ils seront toujours initialisés avant que le constructeur ne soit appelé ;
  2. Dans le constructeur pour la classe ;
  3. Juste avant d'utiliser l'objet, ce qui est souvent appelé initialisation paresseuse.
t t t
n. It can reduce overhead in situations where the object doesn’t need to be created every time. t Cela peut réduire la surcharge dans les situations où l'objet n'a pas besoin d'être créé à chaque fois.
t t t
All three approaches are shown here: t Les trois approches sont montrées ici:
t t t
//: c06:Bath.java
// Constructor initialization with composition.

class Soap {
  private String s;
  Soap() {
    System.out.println("Soap()");
    s = new String("Constructed");
  }
  public String toString() { return s; }
}

public class Bath {
  private String
    // Initializing at point of definition:
    s1 = new String("Happy"),
    s2 = "Happy",
    s3, s4;
  Soap castille;
  int i;
  float toy;
  Bath() {
    System.out.println("Inside Bath()");
    s3 = new String("Joy");
    i = 47;
    toy = 3.14f;
    castille = new Soap();
  }
  void print() {
    // Delayed initialization:
    if(s4 == null)
      s4 = new String("Joy");
    System.out.println("s1 = " + s1);
    System.out.println("s2 = " + s2);
    System.out.println("s3 = " + s3);
    System.out.println("s4 = " + s4);
    System.out.println("i = " + i);
    System.out.println("toy = " + toy);
    System.out.println("castille = " + castille);
  }
  public static void main(String[] args) {
    Bath b = new Bath();
    b.print();
  }
} ///:~
t
// ! c06:Bath.java
// Initialisation dans le constructeur avec composition.

class Soap {
  private String s;
  Soap() {
    System.out.println("Soap()");
    s = new String("Constructed");
  }
  public String toString() { return s; }
}

public class Bath {
  private String
    // Initialisation au moment de la définition:
    s1 = new String("Happy"),
    s2 = "Happy",
    s3, s4;
  Soap castille;
  int i;
  float toy;
  Bath() {
    System.out.println("Inside Bath()");
    s3 = new String("Joy");
    i = 47;
    toy = 3.14f;
    castille = new Soap();
  }
  void print() {
    // Initialisation différée:
    if(s4 == null)
      s4 = new String("Joy");
    System.out.println("s1 = " + s1);
    System.out.println("s2 = " + s2);
    System.out.println("s3 = " + s3);
    System.out.println("s4 = " + s4);
    System.out.println("i = " + i);
    System.out.println("toy = " + toy);
    System.out.println("castille = " + castille);
  }
  public static void main(String[] args) {
    Bath b = new Bath();
    b.print();
  }
} ///:~
t t t
Note that in the Bath constructor a statement is executed before any of the initializations take place. When you don’t initialize at the point of definition, there’s still no guarantee that you’ll perform any initialization before you send a message to an object reference—except for the inevitable run-time exception. t Notez que dans le constructeur de Bath une instruction est exécutée avant que toute initialisation ait lieu. Quand on n'initialise pas au moment de la définition, il n'est pas encore garanti qu'on exécutera une initialisation avant qu'on envoie un message à un objet — sauf l'inévitable exception à l'exécution.
t t t
Here’s the output for the program: t Ici la sortie pour le programme est :
t t t
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
t
Inside Bath()
Soap()
s1 = Happy
s2 = Happy
s3 = Joy
s4 = Joy
i = 47
toy = 3.14
castille = Constructed
t t t
When print( ) is called it fills in s4 so that all the fields are properly initialized by the time they are used. t Quand print( ) est appelé, il remplit s4 donc tout les champs sont proprement initialisés au moment où ils sont utilisés.
t t t

Inheritance syntax

t

La syntaxe de l'héritage

t t t
Inheritance is an integral part of Java (and OOP languages in general). It turns out that you’re always doing inheritance when you create a class, because unless you explicitly inherit from some other class, you implicitly inherit from Java’s standard root class Object. t L'héritage est une partie primordiale de Java (et des langages de programmation par objets en général). Il s'avère qu'on utilise toujours l'héritage quand on veut créer une classe, parce qu'à moins d'hériter explicitement d'une autre classe, on hérite implicitement de la classe racine standard Object.
t t t
The syntax for composition is obvious, but to perform inheritance there’s a distinctly different form. When you inherit, you say “This new class is like that old class.” You state this in code by giving the name of the class as usual, but before the opening brace of the class body, put the keyword extends followed by the name of the base class. When you do this, you automatically get all the data members and methods in the base class. Here’s an example: t La syntaxe de composition est évidente, mais pour réaliser l'héritage il y a une forme distinctement différente. Quand on hérite, on dit « Cette nouvelle classe est comme l'ancienne classe ». On stipule ceci dans le code en donnant le nom de la classe comme d'habitude, mais avant l'accolade ouvrante du corps de la classe, on met le mot clé extends suivi par le nom de la classe de base. Quand on fait cela, on récupère automatiquement toutes les données membres et méthodes de la classe de base. Voici un exemple:
t t t
//: c06:Detergent.java
// Inheritance syntax & properties.

class Cleanser {
  private String s = new String("Cleanser");
  public void append(String a) { s += a; }
  public void dilute() { append(" dilute()"); }
  public void apply() { append(" apply()"); }
  public void scrub() { append(" scrub()"); }
  public void print() { System.out.println(s); }
  public static void main(String[] args) {
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    x.print();
  }
}

public class Detergent extends Cleanser {
  // Change a method:
  public void scrub() {
    append(" Detergent.scrub()");
    super.scrub(); // Call base-class version
  }
  // Add methods to the interface:
  public void foam() { append(" foam()"); }
  // Test the new class:
  public static void main(String[] args) {
    Detergent x = new Detergent();
    x.dilute();
    x.apply();
    x.scrub();
    x.foam();
    x.print();
    System.out.println("Testing base class:");
    Cleanser.main(args);
  }
} ///:~
t
// ! c06:Detergent.java
// Syntaxe d'héritage & propriétés.

class Cleanser {
  private String s = new String("Cleanser");
  public void append(String a) { s += a; }
  public void dilute() { append(" dilute()"); }
  public void apply() { append(" apply()"); }
  public void scrub() { append(" scrub()"); }
  public void print() { System.out.println(s); }
  public static void main(String[] args) {
    Cleanser x = new Cleanser();
    x.dilute(); x.apply(); x.scrub();
    x.print();
  }
}

public class Detergent extends Cleanser {
  // Change une méthode:
  public void scrub() {
    append(" Detergent.scrub()");
    super.scrub(); // Appel de la version de la classe de base
  }
  // Ajoute une méthode à l'interface:
  public void foam() { append(" foam()"); }
  // Test de la nouvelle classe:
  public static void main(String[] args) {
    Detergent x = new Detergent();
    x.dilute();
    x.apply();
    x.scrub();
    x.foam();
    x.print();
    System.out.println("Testing base class:");
    Cleanser.main(args);
  }
} ///:~
t t t
This demonstrates a number of features. First, in the Cleanser append( ) method, Strings are concatenated to s using the += operator, which is one of the operators (along with ‘+’) that the Java designers “overloaded” to work with Strings. t Ceci montre un certain nombre de caractéristiques. Premièrement, dans Cleanser la méthode append( ), les Strings sont concaténées dans s en utilisant l'opérateur +=, qui est l'un des opérateurs (avec « + ») que les créateurs de Java « ont surchargé » pour travailler avec les Strings.
t t t
Second, both Cleanser and Detergent contain a main( ) method. You can create a main( ) for each one of your classes, and it’s often recommended to code this way so that your test code is wrapped in with the class. Even if you have a lot of classes in a program, only the main( ) for the class invoked on the command line will be called. (As long as main( ) is public, it doesn’t matter whether the class that it’s part of is public.) So in this case, when you say java Detergent, Detergent.main( ) will be called. But you can also say java Cleanser to invoke Cleanser.main( ), even though Cleanser is not a public class. This technique of putting a main( ) in each class allows easy unit testing for each class. And you don’t need to remove the main( ) when you’re finished testing; you can leave it in for later testing. t Deuxièmement, tant Cleanser que Detergent contiennent une méthode main( ). On peut créer une main( ) pour chacune de nos classes, et il est souvent recommandé de coder de cette manière afin de garder le code de test dans la classe. Même si on a beaucoup de classes dans un programme, seulement la méthode main( ) pour une classe invoquée sur la ligne de commande sera appelée. Aussi longtemps que main( ) est public, il importe peu que la classe dont elle fait partie soit public ou non. Donc dans ce cas, quand on écrit java Detergent, Detergent.main( ) sera appelée. Mais on peut également écrire java Cleanser pour invoquer Cleanser.main( ), même si Cleanser n'est pas une classe public. Cette technique de mettre une main( ) dans chaque classe permet de tester facilement chaque classe. Et on n'a pas besoin d'enlever la méthode main( ) quand on a finit de tester ; on peut la laisser pour tester plus tard.
t t t
Here, you can see that Detergent.main( ) calls Cleanser.main( ) explicitly, passing it the same arguments from the command line (however, you could pass it any String array). t Ici, on peut voir que Detergent.main( ) appelle Cleanser.main( ) explicitement, en passant les même arguments depuis la ligne de commande (quoiqu'il en soit, on peut passer n'importe quel tableau de String).
t t t
It’s important that all of the methods in Cleanser are public. Remember that if you leave off any access specifier the member defaults to “friendly,” which allows access only to package members. Thus, within this package, anyone could use those methods if there were no access specifier. Detergent would have no trouble, for example. However, if a class from some other package were to inherit from Cleanser it could access only public members. So to plan for inheritance, as a general rule make all fields private and all methods public. (protected members also allow access by derived classes; you’ll learn about this later.) Of course, in particular cases you must make adjustments, but this is a useful guideline. t Il est important que toutes les méthodes de Cleanser soient public. Il faut se souvenir que si on néglige tout modifieur d'accès, par défaut l'accès sera « friendly », lequel permet d'accéder seulement aux membres du même package. Donc, au sein d'un même package, n'importe qui peut utiliser ces méthodes s'il n'y a pas de spécificateur d'accès. Detergent n'aurait aucun problème, par exemple. Quoiqu'il en soit, si une classe d'un autre package devait hériter de Cleanser il pourrait accéder seulement aux membres public. Donc pour planifier l'héritage, en règle générale mettre tous les champs private et toutes les méthodes public (les membres protected permettent également d'accéder depuis une classe dérivée ; nous verrons cela plus tard). Bien sûr, dans des cas particuliers on devra faire des ajustements, mais cela est une règle utile.
t t t
Note that Cleanser has a set of methods in its interface: append( ), dilute( ), apply( ), scrub( ), and print( ). Because Detergent is derived from Cleanser (via the extends keyword) it automatically gets all these methods in its interface, even though you don’t see them all explicitly defined in Detergent. You can think of inheritance, then, as reusing the interface. (The implementation also comes with it, but that part isn’t the primary point.) t Notez que Cleanser contient un ensemble de méthodes dans son interface : append( ), dilute( ), apply( ), scrub( ), et print( ). Parce que Detergent est dérivé de Cleanser (à l'aide du mot-clé extends) il récupère automatiquement toutes les méthodes de son interface , même si elles ne sont pas toutes définies explicitement dans Detergent. On peut penser à l'héritage comme à une réutilisation de l'interface (l'implémentation vient également avec elle, mais ceci n'est pas le point principal).
t t t
As seen in scrub( ), it’s possible to take a method that’s been defined in the base class and modify it. In this case, you might want to call the method from the base class inside the new version. But inside scrub( ) you cannot simply call scrub( ), since that would produce a recursive call, which isn’t what you want. To solve this problem Java has the keyword super that refers to the “superclass” that the current class has been inherited from. Thus the expression super.scrub( ) calls the base-class version of the method scrub( ). t Comme vu dans scrub( ), il est possible de prendre une méthode qui a été définie dans la classe de base et la modifier. Dans ce cas, on pourrait vouloir appeler la méthode de la classe de base dans la nouvelle version. Mais à l'intérieur de scrub( ) on ne peut pas simplement appeler scrub( ), car cela produirait un appel récursif, ce qui n'est pas ce que l'on veut. Pour résoudre ce problème, Java a le mot-clé super qui réfère à la super classe de la classe courante. Donc l'expression super.scrub( ) appelle la version de la classe de base de la méthode scrub( ).
t t t
When inheriting you’re not restricted to using the methods of the base class. You can also add new methods to the derived class exactly the way you put any method in a class: just define it. The method foam( ) is an example of this. t Quand on hérite, on n'est pas tenu de n'utiliser que les méthodes de la classe de base. On peut également ajouter de nouvelles méthodes à la classe dérivée exactement de la manière dont on met une méthode dans une classe : il suffit de la définir. La méthode foam( ) en est un exemple.
t t t
In Detergent.main( ) you can see that for a Detergent object you can call all the methods that are available in Cleanser as well as in Detergent (i.e., foam( )). t Dans Detergent.main( ) on peut voir que pour un objet Detergent on peut appeler toutes les méthodes disponible dans Cleanser aussi bien que dans Detergent (e.g., foam( )).
t t t

Initializing the base class

t

Initialiser la classe de base

t t t
Since there are now two classes involved—the base class and the derived class—instead of just one, it can be a bit confusing to try to imagine the resulting object produced by a derived class. From the outside, it looks like the new class has the same interface as the base class and maybe some additional methods and fields. But inheritance doesn’t just copy the interface of the base class. When you create an object of the derived class, it contains within it a subobject of the base class. This subobject is the same as if you had created an object of the base class by itself. It’s just that, from the outside, the subobject of the base class is wrapped within the derived-class object. t Depuis qu'il y a deux classes concernées - la classe de base et la classe dérivée - au lieu d'une seule, il peut être un peu troublant d'essayer d'imaginer l'objet résultant produit par la classe dérivée. De l'extérieur, il semble que la nouvelle classe a la même interface que la classe de base et peut-être quelques méthodes et champs additionnels. Mais l'héritage ne se contente pas simplement de copier l'interface de la classe de base. Quand on créée un objet de la classe dérivée, il contient en lui un sous-objet de la classe de base. Ce sous-objet est le même que si on crée un objet de la classe de base elle-même. C'est simplement que, depuis l'extérieur, le sous-objet de la classe de base est enrobé au sein de l'objet de la classe dérivée.
t t t
Of course, it’s essential that the base-class subobject be initialized correctly and there’s only one way to guarantee that: perform the initialization in the constructor, by calling the base-class constructor, which has all the appropriate knowledge and privileges to perform the base-class initialization. Java automatically inserts calls to the base-class constructor in the derived-class constructor. The following example shows this working with three levels of inheritance: t Bien sûr, il est essentiel que le sous-objet de la classe de base soit correctement initialisé et il y a un seul moyen de garantir cela: exécuter l'initialisation dans le constructeur, en appelant la constructeur de la classe de base, lequel a tous les connaissances et les privilèges appropriés pour exécuter l'initialisation de la classe de base. Java insère automatiquement les appels au constructeur de la classe de base au sein du constructeur de la classe dérivée. L'exemple suivant montre comment cela fonctionne avec 3 niveaux d'héritage : 
t t t
//: c06:Cartoon.java
// Constructor calls during inheritance.

class Art {
  Art() {
    System.out.println("Art constructor");
  }
}

class Drawing extends Art {
  Drawing() {
    System.out.println("Drawing constructor");
  }
}

public class Cartoon extends Drawing {
  Cartoon() {
    System.out.println("Cartoon constructor");
  }
  public static void main(String[] args) {
    Cartoon x = new Cartoon();
  }
} ///:~
t
// ! c06:Cartoon.java
// Appels de constructeur durant l'initialisation

class Art {
  Art() {
    System.out.println("Art constructor");
  }
}

class Drawing extends Art {
  Drawing() {
    System.out.println("Drawing constructor");
  }
}

public class Cartoon extends Drawing {
  Cartoon() {
    System.out.println("Cartoon constructor");
  }
  public static void main(String[] args) {
    Cartoon x = new Cartoon();
  }
} ///:~
t t t
The output for this program shows the automatic calls: t La sortie de ce programme montre les appels automatiques:
t t t
Art constructor
Drawing constructor
Cartoon constructor
t
Art constructor
Drawing constructor
Cartoon constructor
t t t
You can see that the construction happens from the base “outward,” so the base class is initialized before the derived-class constructors can access it. t On peut voir que la construction commence par la classe la plus haute dans la hiérarchie, donc la classe de base est initialisée avant que les constructeurs de la classe dérivée puisse y accéder.
t t t
Even if you don’t create a constructor for Cartoon( ), the compiler will synthesize a default constructor for you that calls the base class constructor. t Même si on ne crée pas de constructeur pour Cartoon( ), le compilateur fournira un constructeur.
t t t

Constructors with arguments

t

Constructeurs avec paramètres

t t t
The above example has default constructors; that is, they don’t have any arguments. It’s easy for the compiler to call these because there’s no question about what arguments to pass. If your class doesn’t have default arguments, or if you want to call a base-class constructor that has an argument, you must explicitly write the calls to the base-class constructor using the super keyword and the appropriate argument list: t L'exemple ci-dessus a des constructeurs par défaut ; ils n'ont pas de paramètres. C'est facile pour le compilateur d'appeler ceux-ci parce qu'il n'y a pas de questions à se poser au sujet des arguments à passer. Si notre classe n'a pas de paramètres par défaut, ou si on veut appeler le constructeur d'une classe de base avec paramètre, on doit explicitement écrire les appels au contructeur de la classe de base en utilisant le mot clé super ainsi que la liste de paramètres appropriée  : super et la liste de paramètres appropriée:
t t t
//: c06:Chess.java
// Inheritance, constructors and arguments.

class Game {
  Game(int i) {
    System.out.println("Game constructor");
  }
}

class BoardGame extends Game {
  BoardGame(int i) {
    super(i);
    System.out.println("BoardGame constructor");
  }
}

public class Chess extends BoardGame {
  Chess() {
    super(11);
    System.out.println("Chess constructor");
  }
  public static void main(String[] args) {
    Chess x = new Chess();
  }
} ///:~
t
// ! c06:Chess.java
// Héritage, constructeurs et paramètres.

class Game {
  Game(int i) {
    System.out.println("Game constructor");
  }
}

class BoardGame extends Game {
  BoardGame(int i) {
    super(i);
    System.out.println("BoardGame constructor");
  }
}

public class Chess extends BoardGame {
  Chess() {
    super(11);
    System.out.println("Chess constructor");
  }
  public static void main(String[] args) {
    Chess x = new Chess();
  }
} ///:~
t t t
If you don’t call the base-class constructor in BoardGame( ), the compiler will complain that it can’t find a constructor of the form Game( ). In addition, the call to the base-class constructor must be the first thing you do in the derived-class constructor. (The compiler will remind you if you get it wrong.) t Si on n'appelle pas le constructeur de la classe de base dans BoardGame( ), le compilateur va se plaindre qu'il ne peut pas trouver le constructeur de la forme Game( ). De plus, l'appel du constructeur de la classe de base doit être la première chose que l'on fait dans le constructeur de la classe dérivée. Le compilateur va le rappeler si on se trompe.
t t t
t t t
t t
    
///
t t t
t
     
Sommaire Le site de Bruce Eckel