t
t
t
t
t t   6) Réutiliser les classes
tttt
t
carrea) Préface carreb) Avant-propos carre1) Introduction sur les &laqo; objets » carre2) Tout est &laqo; objet » carre3) Contrôle du flux du programme carre4) Initialization & Cleanup carre5) Cacher l'implémentation 6) Réutiliser les classes carre7) Polymorphisme carre8) Interfaces & classes internes carre9) Stockage des objets carre10) Error Handling with Exceptions carre11) Le système d’E/S de Java carre12) Identification dynamique de type carre13) Création de fenêtres & d'Applets carre14) Les &laqo; Threads » multiples carre15) Informatique distribuée carreA) Passage et retour d'objets carreB) L'Interface Java Natif (JNI) carreC) Conseils pour une programation stylée en Java carreD) Resources
Texte original t Traducteur : Olivier Thomann
t
t
///
Ce chapitre contient 4 pages
1 2 3 4
\\\
t t t
t t t
t
t t t
What’s interesting in this example is the tune( ) method, which accepts an Instrument reference. However, in Wind.main( ) the tune( ) method is called by giving it a Wind reference. Given that Java is particular about type checking, it seems strange that a method that accepts one type will readily accept another type, until you realize that a Wind object is also an Instrument object, and there’s no method that tune( ) could call for an Instrument that isn’t also in Wind. Inside tune( ), the code works for Instrument and anything derived from Instrument, and the act of converting a Wind reference into an Instrument reference is called upcasting.
t Le point intéressant de cet exemple est la méthode tune( ), qui accepte une référence Instrument. Cependant, dans Wind.main( ) la méthode tune( ) est appelée en lui donnant une référence Wind. Étant donné que Java est strict au sujet de la vérification de type, il semble étrange qu'une méthode qui accepte un type acceptera littéralement un autre type jusqu'à ce qu'on réalise qu'un objet Wind est également un objet Instrument, et il n'y a pas de méthode que tune( ) pourrait appeler pour un Instrument qui ne serait également dans Wind. À l'intérieur de tune( ), le code fonctionne pour Instrument et tout ce qui dérive de Instrument, et l'acte de convertir une référence Wind en une référence Instrument est appelé transtypage ascendant.
t t t

Why “upcasting”?

t

Pourquoi le transtypage ascendant ? 

t t t
The reason for the term is historical, and based on the way class inheritance diagrams have traditionally been drawn: with the root at the top of the page, growing downward. (Of course, you can draw your diagrams any way you find helpful.) The inheritance diagram for Wind.java is then:

t La raison de ce terme est historique et basée sur la manière dont les diagrammes d'héritage ont été traditionnellement dessinés :  avec la racine au sommet de la page, et grandissant vers le bas. Bien sûr vous pouvez dessiner vos diagrammes de la manière que vous trouvez le plus pratique. Le diagramme d'héritage pour Wind.java est :  image
t t t
Casting from derived to base moves up on the inheritance diagram, so it’s commonly referred to as upcasting. Upcasting is always safe because you’re going from a more specific type to a more general type. That is, the derived class is a superset of the base class. It might contain more methods than the base class, but it must contain at least the methods in the base class. The only thing that can occur to the class interface during the upcast is that it can lose methods, not gain them. This is why the compiler allows upcasting without any explicit casts or other special notation.
t Transtyper depuis une classe dérivée vers la classe de base nous déplace vers le haut dans le diagramme, on fait donc communément référence à un transtypage ascendant. Le transtypage ascendant est toujours sans danger parce qu'on va d'un type plus spécifique vers un type plus général. La classe dérivée est un sur-ensemble de la classe de base. Elle peut contenir plus de méthodes que la classe de base, mais elle contient au moins les méthodes de la classe de base. La seule chose qui puisse arriver à une classe pendant le transtypage ascendant est de perdre des méthodes et non en gagner. C'est pourquoi le compilateur permet le transtypage ascendant sans transtypage explicite ou une notation spéciale.
t t t
You can also perform the reverse of upcasting, called downcasting, but this involves a dilemma that is the subject of Chapter 12.
t On peut également faire l'inverse du transtypage ascendant, appelé transtypage descendant, mais cela génère un dilemme qui est le sujet du chapitre 12.
t t t

Composition vs. inheritance revisited

t

Composition à la place de l'héritage revisité

t t t
In object-oriented programming, the most likely way that you’ll create and use code is by simply packaging data and methods together into a class, and using objects of that class. You’ll also use existing classes to build new classes with composition. Less frequently, you’ll use inheritance. So although inheritance gets a lot of emphasis while learning OOP, it doesn’t mean that you should use it everywhere you possibly can. On the contrary, you should use it sparingly, only when it’s clear that inheritance is useful. One of the clearest ways to determine whether you should use composition or inheritance is to ask whether you’ll ever need to upcast from your new class to the base class. If you must upcast, then inheritance is necessary, but if you don’t need to upcast, then you should look closely at whether you need inheritance. The next chapter (polymorphism) provides one of the most compelling reasons for upcasting, but if you remember to ask “Do I need to upcast?” you’ll have a good tool for deciding between composition and inheritance.
t En programmation orienté objet, la manière la plus probable pour créer et utiliser du code est simplement de mettre des méthodes et des données ensemble dans une classe puis d'utiliser les objets de cette classe. On utilisera également les classes existantes pour construire les nouvelles classes avec la composition. Moins fréquemment on utilisera l'héritage. Donc bien qu'on insiste beaucoup sur l'héritage en apprenant la programmation orientée objet, cela ne signifie pas qu'on doive l'utiliser partout où l'on peut. Au contraire, on devrait l'utiliser avec parcimonie, seulement quand il est clair que l'héritage est utile. Un des moyens les plus clairs pour déterminer si on doit utiliser la composition ou l'héritage est de se demander si on aura jamais besoin de faire un transtypage ascendant de la nouvelle classe vers la classe de base. Si on doit faire un transtypage ascendant, alors l'héritage est nécessaire, mais si on n'a pas besoin de faire un transtypage ascendant, alors il faut regarder avec attention pour savoir si on a besoin de l'héritage. Le prochain chapitre (polymorphisme) fournit une des plus excitantes raisons pour le transtypage ascendant, mais si vous vous rappelez de vous demander « Ai-je besoin de transtypage ascendant ? », vous aurez un bon outil pour décider entre composition et héritage.
t t t

The final keyword

t

Le mot clé final

t t t
Java’s final keyword has slightly different meanings depending on the context, but in general it says “This cannot be changed.” You might want to prevent changes for two reasons: design or efficiency. Because these two reasons are quite different, it’s possible to misuse the final keyword.
t Le mot clé Java final a des sens légèrement différents suivant le contexte, mais en général il signifie « Cela ne peut pas changer ». Vous pourriez vouloir empêcher les changements pour deux raisons : conception ou efficacité. Parce que ces deux raisons sont quelque peu différentes, il est possible de mal utiliser le mot clé final.
t t t
The following sections discuss the three places where final can be used: for data, methods, and classes.
t Les sections suivantes parlent des trois endroits où le mot clé final peut être utilisé : données, méthodes et classes.
t t t

Final data

t

Données finales

t t t
Many programming languages have a way to tell the compiler that a piece of data is “constant.” A constant is useful for two reasons:
t Beaucoup de langages de programmation ont un moyen de dire au compilateur que cette donnée est constante. Une constante est utile pour deux raisons:
t t t
  1. It can be a compile-time constant that won’t ever change.
  2. It can be a value initialized at run-time that you don’t want changed.
t
  1. Elle peut être une constante lors de la compilation qui ne changera jamais ; 
  2. Elle peut être une valeur initialisée à l'exécution qu'on ne veut pas changer.
t t t
In the case of a compile-time constant, the compiler is allowed to “fold” the constant value into any calculations in which it’s used; that is, the calculation can be performed at compile-time, eliminating some run-time overhead. In Java, these sorts of constants must be primitives and are expressed using the final keyword. A value must be given at the time of definition of such a constant.
t Dans le cas d'une constante à la compilation, le compilateur inclut « en dur » la valeur de la constante pour tous les calculs où elle intervient  ; dans ce cas, le calcul peut être effectué à la compilation, éliminant ainsi un surcoût à l'exécution. En Java, ces sortes de constantes doivent être des primitives et sont exprimées en utilisant le mot-clé final. Une valeur doit être donnée au moment de la définition d'une telle constante.
t t t
A field that is both static and final has only one piece of storage that cannot be changed.
t Un champ qui est à la fois static et final a un emplacement de stockage fixe qui ne peut pas être changé.
t t t
When using final with object references rather than primitives the meaning gets a bit confusing. With a primitive, final makes the value a constant, but with an object reference, final makes the reference a constant. Once the reference is initialized to an object, it can never be changed to point to another object. However, the object itself can be modified; Java does not provide a way to make any arbitrary object a constant. (You can, however, write your class so that objects have the effect of being constant.) This restriction includes arrays, which are also objects.
t Quand on utilise final avec des objets références plutôt qu'avec des types primitifs la signification devient un peu confuse. Avec un type primitif, final fait de la valeur une constante, mais avec un objet référence, final fait de la « référence » une constante. Une fois la référence liée à un objet, elle ne peut jamais changer pour pointer vers un autre objet. Quoiqu'il en soit, l'objet lui même peut être modifié ; Java ne fournit pas de moyen de rendre un objet arbitraire une constante. On peut quoiqu'il en soit écrire notre classe de manière que les objets paraissent constants. Cette restriction inclut les tableaux, qui sont également des objets.
t t t
Here’s an example that demonstrates final fields:
t Voici un exemple qui montre les champs final:
t t t
//: c06:FinalData.java // The effect of final on fields. class Value { int i = 1; } public class FinalData { // Can be compile-time constants final int i1 = 9; static final int VAL_TWO = 99; // Typical public constant: public static final int VAL_THREE = 39; // Cannot be compile-time constants: final int i4 = (int)(Math.random()*20); static final int i5 = (int)(Math.random()*20); Value v1 = new Value(); final Value v2 = new Value(); static final Value v3 = new Value(); // Arrays: final int[] a = { 1, 2, 3, 4, 5, 6 }; public void print(String id) { System.out.println( id + ": " + "i4 = " + i4 + ", i5 = " + i5); } public static void main(String[] args) { FinalData fd1 = new FinalData(); //! fd1.i1++; // Error: can't change value fd1.v2.i++; // Object isn't constant! fd1.v1 = new Value(); // OK -- not final for(int i = 0; i < fd1.a.length; i++) fd1.a[i]++; // Object isn't constant! //! fd1.v2 = new Value(); // Error: Can't //! fd1.v3 = new Value(); // change reference //! fd1.a = new int[3]; fd1.print("fd1"); System.out.println("Creating new FinalData"); FinalData fd2 = new FinalData(); fd1.print("fd1"); fd2.print("fd2"); } } ///:~ t
// ! c06:FinalData.java
// L'effet de final sur les champs.

class Value {
  int i = 1;
}

public class FinalData {
  // Peut être des constantes à la compilation
  final int i1 = 9;
  static final int VAL_TWO = 99;
  // Constantes publiques typiques:
  public static final int VAL_THREE = 39;
  // Ne peuvent pas être des constantes à la compilation:
  final int i4 = (int)(Math.random()*20);
  static final int i5 = (int)(Math.random()*20);
  
  Value v1 = new Value();
  final Value v2 = new Value();
  static final Value v3 = new Value();
  // Tableaux:
  final int[] a = { 1, 2, 3, 4, 5, 6 };

  public void print(String id) {
    System.out.println(
      id + " : " + "i4 = " + i4 +
      ", i5 = " + i5);
  }
  public static void main(String[] args) {
    FinalData fd1 = new FinalData();
    // ! fd1.i1++; // Erreur : on ne peut pas changer la valeur
    fd1.v2.i++; // L'objet n'est pas une constante!
    fd1.v1 = new Value(); // OK -- non final
    for(int i = 0; i < fd1.a.length; i++)
      fd1.a[i]++; // L'objet n'est pas une constante!
    // ! fd1.v2 = new Value(); // Erreur : Ne peut pas
    // ! fd1.v3 = new Value(); // changer la référence
    // ! fd1.a = new int[3];

    fd1.print("fd1");
    System.out.println("Creating new FinalData");
    FinalData fd2 = new FinalData();
    fd1.print("fd1");
    fd2.print("fd2");
  }
} ///:~
t t t
Since i1 and VAL_TWO are final primitives with compile-time values, they can both be used as compile-time constants and are not different in any important way. VAL_THREE is the more typical way you’ll see such constants defined: public so they’re usable outside the package, static to emphasize that there’s only one, and final to say that it’s a constant. Note that final static primitives with constant initial values (that is, compile-time constants) are named with all capitals by convention, with words separated by underscores (This is just like C constants, which is where the convention originated.) Also note that i5 cannot be known at compile-time, so it is not capitalized.
t Etant donné que i1 et VAL_TWO sont des primitives final ayant une valeur à la compilation, elles peuvent être toutes les deux utilisées comme constantes à la compilation et ne sont pas vraiment différentes. VAL_THREE nous montre la manière la plus typique de définir ces constantes : public afin qu'elles puissent être utilisées en dehors du package, static pour souligner qu'il ne peut y en avoir qu'une seulement, et final pour dire que c'est une constante. Notez que les primitives final static avec des valeurs initiales constantes (ce sont des constantes à la compilation) sont nommées avec des lettre capitales par convention, avec des mots séparés par des underscores. Ce sont comme des constantes C, d'où cette convention est originaire. Notons également que i5 ne peut pas être connu à la compilation, donc elle n'est pas en lettres capitales.
t t t
Just because something is final doesn’t mean that its value is known at compile-time. This is demonstrated by initializing i4 and i5 at run-time using randomly generated numbers. This portion of the example also shows the difference between making a final value static or non-static. This difference shows up only when the values are initialized at run-time, since the compile-time values are treated the same by the compiler. (And presumably optimized out of existence.) The difference is shown in the output from one run:
t Le fait que quelque chose soit final ne signifie pas que sa valeur est connue à la compilation. Ceci est montré par l'initialisation de i4 et i5 à l'exécution en utilisant des nombres générés aléatoirement. La portion de cet exemple montre également la différence entre mettre une valeur final static ou non static. Cette différence n'est visible que quand les valeurs sont initialisées à l'exécution, tandis que les valeurs à la compilation sont traitées de même par le compilateur. Et vraisemblablement optimisées à la compilation. La différence est montrée par la sortie d'une exécution:
t t t
fd1: i4 = 15, i5 = 9 Creating new FinalData fd1: i4 = 15, i5 = 9 fd2: i4 = 10, i5 = 9 t
fd1 : i4 = 15, i5 = 9
Creating new FinalData
fd1 : i4 = 15, i5 = 9
fd2 : i4 = 10, i5 = 9
t t t
Note that the values of i4 for fd1 and fd2 are unique, but the value for i5 is not changed by creating the second FinalData object. That’s because it’s static and is initialized once upon loading and not each time a new object is created.
t Notez que les valeurs de i4 pour fd1 et fd2 sont uniques, mais la valeur de i5 n'est pas changée en créant un second objet FinalData. C'est parce qu'elle est static et initialisée une fois pour toutes lors du chargement et non à chaque fois qu'un nouvel objet est créé.
t t t
The variables v1 through v4 demonstrate the meaning of a final reference. As you can see in main( ), just because v2 is final doesn’t mean that you can’t change its value. However, you cannot rebind v2 to a new object, precisely because it’s final. That’s what final means for a reference. You can also see the same meaning holds true for an array, which is just another kind of reference. (There is no way that I know of to make the array references themselves final.) Making references final seems less useful than making primitives final.
t Les variables v1 jusqu'à v4 montre le sens de références final. Comme on peut le voir dans main(), le fait que v2 soit final ne signifie pas qu'on ne peut pas changer sa valeur. Quoiqu'il en soit, on ne peut pas réaffecter un nouvel objet à v2, précisément parce qu'il est final. C'est ce que final signifie pour une référence. On peut également voir que ce sens reste vrai pour un tableau, qui est une autre sorte de référence. Il n'y a aucun moyen de savoir comment rendre les références du tableau elle-mêmes final. Mettre les références final semble moins utile que mettre les primitives final.
t t t

Blank finals

t

Finals sans initialisation

t t t
Java allows the creation of blank finals, which are fields that are declared as final but are not given an initialization value. In all cases, the blank final must be initialized before it is used, and the compiler ensures this. However, blank finals provide much more flexibility in the use of the final keyword since, for example, a final field inside a class can now be different for each object and yet it retains its immutable quality. Here’s an example:
t Java permet la création de finals sans initialisation, qui sont des champs déclarés final, mais n'ont pas de valeur d'initialisation. Dans tous les cas, un final sans initialisation doit être initialisé avant d'être utilisé, et le compilateur doit s'en assurer. Quoiqu'il en soit, les finals sans initialisation fournissent bien plus de flexibilité dans l'usage du mot-clé final depuis que, par exemple, un champ final à l'intérieur d'une classe peut maintenant être différent pour chaque objet tout en gardant son caractère immuable. Voici un exemple:
t t t
//: c06:BlankFinal.java // "Blank" final data members. class Poppet { } class BlankFinal { final int i = 0; // Initialized final final int j; // Blank final final Poppet p; // Blank final reference // Blank finals MUST be initialized // in the constructor: BlankFinal() { j = 1; // Initialize blank final p = new Poppet(); } BlankFinal(int x) { j = x; // Initialize blank final p = new Poppet(); } public static void main(String[] args) { BlankFinal bf = new BlankFinal(); } } ///:~ t
// ! c06:BlankFinal.java
// Les membres des données final sans initialisation

class Poppet { }

class BlankFinal {
  final int i = 0; // Final initialisé
  final int j; // Final sans initialisation
  final Poppet p; // Référence final sans initialisation
  // Les finals doivent être initialisés
  // dans le constructeur:
  BlankFinal() {
    j = 1; // Initialise le final sans valeur initiale
    p = new Poppet();
  }
  BlankFinal(int x) {
    j = x; // Initialise le final sans valeur initiale
    p = new Poppet();
  }
  public static void main(String[] args) {
    BlankFinal bf = new BlankFinal();
  }
} ///:~
t t t
You’re forced to perform assignments to finals either with an expression at the point of definition of the field or in every constructor. This way it’s guaranteed that the final field is always initialized before use.
t Vous êtes forcés d'initialiser un final soit avec une expression au moment de la définition, soit dans chaque constructeur. De cette manière il est garanti que le champ final sera toujours initialisé avant son utilisation.
t t t

Final arguments

t

Arguments final

t t t
Java allows you to make arguments final by declaring them as such in the argument list. This means that inside the method you cannot change what the argument reference points to:
t Java permet de définir les arguments final en les déclarant comme tels dans la liste des arguments. Cela signifie qu'à l'intérieur de la méthode on ne peut pas changer ce vers quoi pointe l'argument:
t t t
//: c06:FinalArguments.java // Using "final" with method arguments. class Gizmo { public void spin() {} } public class FinalArguments { void with(final Gizmo g) { //! g = new Gizmo(); // Illegal -- g is final } void without(Gizmo g) { g = new Gizmo(); // OK -- g not final g.spin(); } // void f(final int i) { i++; } // Can't change // You can only read from a final primitive: int g(final int i) { return i + 1; } public static void main(String[] args) { FinalArguments bf = new FinalArguments(); bf.without(null); bf.with(null); } } ///:~ t
// ! c06:FinalArguments.java
// Utilisation de « final » dans les arguments d'une méthode.

class Gizmo {
  public void spin() {}
}

public class FinalArguments {
  void with(final Gizmo g) {
    // ! g = new Gizmo(); // Illégal -- g est final
  }
  void without(Gizmo g) {
    g = new Gizmo(); // OK -- g n'est pas final
    g.spin();
  }
  // void f(final int i) { i++; } // Ne peut pas changer
  // On peut seulement lire depuis une primitive final:
  int g(final int i) { return i + 1; }
  public static void main(String[] args) {
    FinalArguments bf = new FinalArguments();
    bf.without(null);
    bf.with(null);
  }
} ///:~
t t t
Note that you can still assign a null reference to an argument that’s final without the compiler catching it, just like you can with a non-final argument.
t A noter qu'on peut encore affecter une référence null à un argument qui est final sans que le compilateur ne l'empêche, comme on pourrait le faire pour un argument non-final.
t t t
The methods f( ) and g( ) show what happens when primitive arguments are final: you can read the argument, but you can't change it.
t Les méthodes f( ) et g( ) montre ce qui arrive quand les arguments primitifs sont final: on peut lire l'argument, mais on ne peut pas le changer.
t t t

Final methods

t

Méthodes final

t t t
There are two reasons for final methods. The first is to put a “lock” on the method to prevent any inheriting class from changing its meaning. This is done for design reasons when you want to make sure that a method’s behavior is retained during inheritance and cannot be overridden.
t Les méthodes final ont deux raisons d'être. La première est de mettre un « verrou » sur la méthode pour empêcher toute sous-classe de la redéfinir. Ceci est fait pour des raisons de conception quand on veut être sûr que le comportement d'une méthode est préservé durant l'héritage et ne peut pas être redéfini.
t t t
The second reason for final methods is efficiency. If you make a method final, you are allowing the compiler to turn any calls to that method into inline calls. When the compiler sees a final method call it can (at its discretion) skip the normal approach of inserting code to perform the method call mechanism (push arguments on the stack, hop over to the method code and execute it, hop back and clean off the stack arguments, and deal with the return value) and instead replace the method call with a copy of the actual code in the method body. This eliminates the overhead of the method call. Of course, if a method is big, then your code begins to bloat and you probably won’t see any performance gains from inlining, since any improvements will be dwarfed by the amount of time spent inside the method. It is implied that the Java compiler is able to detect these situations and choose wisely whether to inline a final method. However, it’s better to not trust that the compiler is able to do this and make a method final only if it’s quite small or if you want to explicitly prevent overriding.
t La deuxième raison est l'efficacité. Si on met une méthode final, on permet au compilateur de convertir tout appel à cette méthode en un appel incorporé. Quand le compilateur voit un appel à une méthode final, il peut à sa discrétion éviter l'approche normale d'insérer du code pour exécuter l'appel de la méthode (mettre les arguments sur la pile, sauter au code de la méthode et l' exécuter, revenir au code courant et nettoyer les arguments de la pile, s'occuper de la valeur de retour) et à la place remplacer l'appel de méthode avec une copie du code de cette méthode dans le corps de la méthode courante. Ceci élimine le surcoût de l'appel de méthode. Bien entendu, si une méthode est importante, votre code commencera alors à grossir et vous ne verrez plus le gain de performance dû au code « incorporé », parce que toute amélioration sera cachée par le temps passé à l'intérieur de la méthode. Ceci implique que le compilateur Java est capable de détecter ces situations et de choisir sagement si oui ou non il faut « incorporer » une méthode final. Quoiqu'il en soit, il est mieux de ne pas faire confiance à ce que peut faire le compilateur et de mettre une méthode final seulement si elle est plutôt petite ou si on veut explicitement empêcher la surcharge.
t t t

final and private

t

final et private

t t t
Any private methods in a class are implicitly final. Because you can’t access a private method, you can’t override it (even though the compiler doesn’t give an error message if you try to override it, you haven’t overridden the method, you’ve just created a new method). You can add the final specifier to a private method but it doesn’t give that method any extra meaning.
t Toutes les méthodes private sont implicitement final. Parce qu'on ne peut pas accéder à une méthode private, on ne peut pas la surcharger (même si le compilateur ne donne pas de messages d'erreur si on essaye de la redéfinir, on ne redéfinit pas la méthode, on a simplement créé une nouvelle méthode). On peut ajouter le mot-clé final à une méthode private, mais ça n'apporte rien de plus.
t t t
This issue can cause confusion, because if you try to override a private method (which is implicitly final) it seems to work:
t Ce problème peut rendre les choses un peu confuses, parce que si on essaye de surcharger une méthode private qui est implicitement final ça semble fonctionner:
t t t
//: c06:FinalOverridingIllusion.java // It only looks like you can override // a private or private final method. class WithFinals { // Identical to "private" alone: private final void f() { System.out.println("WithFinals.f()"); } // Also automatically "final": private void g() { System.out.println("WithFinals.g()"); } } class OverridingPrivate extends WithFinals { private final void f() { System.out.println("OverridingPrivate.f()"); } private void g() { System.out.println("OverridingPrivate.g()"); } } class OverridingPrivate2 extends OverridingPrivate { public final void f() { System.out.println("OverridingPrivate2.f()"); } public void g() { System.out.println("OverridingPrivate2.g()"); } } public class FinalOverridingIllusion { public static void main(String[] args) { OverridingPrivate2 op2 = new OverridingPrivate2(); op2.f(); op2.g(); // You can upcast: OverridingPrivate op = op2; // But you can't call the methods: //! op.f(); //! op.g(); // Same here: WithFinals wf = op2; //! wf.f(); //! wf.g(); } } ///:~ t
// ! c06:FinalOverridingIllusion.java
// C'est seulement une impression qu'on peut
// surcharger une méthode private ou private final.

class WithFinals {
  // Identique à « private » tout seul:
  private final void f() {
    System.out.println("WithFinals.f()");
  }
  // Également automatiquement « final »:
  private void g() {
    System.out.println("WithFinals.g()");
  }
}

class OverridingPrivate extends WithFinals {
  private final void f() {
    System.out.println("OverridingPrivate.f()");
  }
  private void g() {
    System.out.println("OverridingPrivate.g()");
  }
}

class OverridingPrivate2
  extends OverridingPrivate {
  public final void f() {
    System.out.println("OverridingPrivate2.f()");
  }
  public void g() {
    System.out.println("OverridingPrivate2.g()");
  }
}

public class FinalOverridingIllusion {
  public static void main(String[] args) {
    OverridingPrivate2 op2 =
      new OverridingPrivate2();
    op2.f();
    op2.g();
    // On peut faire un transtypage ascendant:
    OverridingPrivate op = op2;
    // Mais on ne peut pas appeler les méthodes:
    // ! op.f();
    // ! op.g();
    // Idem ici:
    WithFinals wf = op2;
    // ! wf.f();
    // ! wf.g();
  }
} ///:~
t t t
“Overriding” can only occur if something is part of the base-class interface. That is, you must be able to upcast an object to its base type and call the same method (the point of this will become clear in the next chapter). If a method is private, it isn’t part of the base-class interface. It is just some code that’s hidden away inside the class, and it just happens to have that name, but if you create a public, protected or “friendly” method in the derived class, there’s no connection to the method that might happen to have that name in the base class. Since a private method is unreachable and effectively invisible, it doesn’t factor into anything except for the code organization of the class for which it was defined.
t « Surcharger » peut seulement arriver si quelque chose fait partie de l'interface de la classe de base. On doit être capable de faire un transtypage ascendant vers la classe de base et d'appeler la même méthode. Ce point deviendra clair dans le prochain chapitre. Si une méthode est private, elle ne fait pas partie de l'interface de la classe de base. C'est simplement du code qui est caché à l'intérieur de la classe, et il arrive simplement qu'elle a ce nom, mais si on définit une méthode public, protected ou « amies » dans la classe dérivée, il n'y a aucune connexion avec la méthode de même nom dans la classe de base. Étant donné qu'une méthode private est inatteignable et effectivement invisible, elle ne sert à rien d'autre qu'à l'organisation du code dans la classe dans laquelle elle est définie.
t t t

Final classes

t

Classes final

t t t
When you say that an entire class is final (by preceding its definition with the final keyword), you state that you don’t want to inherit from this class or allow anyone else to do so. In other words, for some reason the design of your class is such that there is never a need to make any changes, or for safety or security reasons you don’t want subclassing. Alternatively, you might be dealing with an efficiency issue, and you want to make sure that any activity involved with objects of this class are as efficient as possible.
t Quand on dit qu'une classe entière est final (en faisant précéder sa définition par le mot-clé final) on stipule qu'on ne veut pas hériter de cette classe ou permettre à qui que ce soit de le faire. En d'autres mots, soit la conception de cette classe est telle qu'on n'aura jamais besoin de la modifier, soit pour des raisons de sûreté ou de sécurité on ne veut pas qu'elle soit sous-classée. Ou alors, on peut avoir affaire à un problème d'efficacité, et on veut s'assurer que toute activité impliquant des objets de cette classe sera aussi efficace que possible.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel