t t 8) Interfaces et classes internes
8) Interfaces & classes internes
Texte original t Traducteur : Jérome QUELIN
Ce chapitre contient 6 pages
1 2 3 4 5 6
t t t
t t t
t t t
Note that light, water, thermostat, and rings all belong to the outer class GreenhouseControls, and yet the inner classes can access those fields without qualification or special permission. Also, most of the action( ) methods involve some sort of hardware control, which would most likely involve calls to non-Java code. t Notez que light, water, thermostat et rings appartiennent tous à la classe externe GreenhouseControls, et donc les classes internes peuvent accéder à ces champs sans qualification ou permission particulière. De plus, la plupart des méthodes action() effectuent un contrôle hardware, qui implique certainement des appels à du code non-Java.
t t t
Most of the Event classes look similar, but Bell and Restart are special. Bell rings, and if it hasn’t yet rung enough times it adds a new Bell object to the event list, so it will ring again later. Notice how inner classes almost look like multiple inheritance: Bell has all the methods of Event and it also appears to have all the methods of the outer class GreenhouseControls. t La plupart des classes Event sont similaires, mais Bell et Restart sont spéciales. Bell sonne, et si elle n'a pas sonné un nombre suffisant de fois, elle ajoute un nouvel objet Bell à la liste des événements afin de sonner à nouveau plus tard. Notez comme les classes internes semblent bénéficier de l'héritage multiple : Bell possède toutes les méthodes d'Event mais elle semble disposer également de toutes les méthodes de la classe externe GreenhouseControls.
t t t
Restart is responsible for initializing the system, so it adds all the appropriate events. Of course, a more flexible way to accomplish this is to avoid hard-coding the events and instead read them from a file. (An exercise in Chapter 11 asks you to modify this example to do just that.) Since Restart( ) is just another Event object, you can also add a Restart object within Restart.action( ) so that the system regularly restarts itself. And all you need to do in main( ) is create a GreenhouseControls object and add a Restart object to get it going. t Restart est responsable de l'initialisation du système, il ajoute donc tous les événements appropriés. Bien sûr, une manière plus flexible de réaliser ceci serait d'éviter le codage en dur des événements et de les extraire d'un fichier à la place (c'est précisément ce qu'un exercice du Chapitre 11 demande de faire). Puisque Restart() n'est qu'un objet Event comme un autre, on peut aussi ajouter un objet Restart depuis Restart.action() afin que le système se relance de lui-même régulièrement. Et tout ce qu'on a besoin de faire dans main() est de créer un objet GreenhouseControls et ajouter un objet Restart pour lancer le processus.
t t t
This example should move you a long way toward appreciating the value of inner classes, especially when used within a control framework. However, in Chapter 13 you’ll see how elegantly inner classes are used to describe the actions of a graphical user interface. By the time you finish that chapter you should be fully convinced. t Cet exemple devrait vous avoir convaincu de l'intérêt des classes internes, spécialement dans le cas des structures de contrôle. Si ce n'est pas le cas, dans le Chapitre 13, vous verrez comment les classes internes sont utilisées pour décrire élégamment les actions d'une interface graphique utilisateur. A la fin de ce chapitre vous devriez être complètement convaincu.
t t t




t t t
Interfaces and inner classes are more
sophisticated concepts than what you’ll find in many OOP languages. For
example, there’s nothing like them in C++. Together, they solve the same
problem that C++ attempts to solve with its multiple inheritance (MI) feature.
However, MI in C++ turns out to be rather difficult to use, while Java
interfaces and inner classes are, by comparison, much more
t Les interfaces et les classes internes sont des concepts plus sophistiqués que ce que vous pourrez trouver dans beaucoup de langages de programmation orientés objets. Par exemple, rien de comparable n'existe en C++. Ensemble, elles résolvent le même problème que celui que le C++ tente de résoudre avec les fonctionnalités de l'héritage multiple. Cependant, l'héritage multiple en C++ se révèle relativement ardu à mettre en oeuvre, tandis que les interfaces et les classes internes en Java sont, en comparaison, d'un abord nettement plus facile.
t t t
Although the features themselves are
reasonably straightforward, the use of these features is a design issue, much
the same as polymorphism. Over time, you’ll become better at recognizing
situations where you should use an interface, or an inner class, or both. But at
this point in this book you should at least be comfortable with the syntax and
semantics. As you see these language features in use you’ll eventually
internalize them.
t Bien que les fonctionnalités en elles-mêmes soient relativement simples, leur utilisation relève de la conception, de même que le polymorphisme. Avec le temps, vous reconnaîtrez plus facilement les situations dans lesquelles utiliser une interface, ou une classe interne, ou les deux. Mais à ce point du livre vous devriez à tout le moins vous sentir à l'aise avec leur syntaxe et leur sémantique. Vous intègrerez ces techniques au fur et à mesure que vous les verrez utilisées.
t t t




t t t
Solutions to selected exercises
can be found in the electronic document The Thinking in Java Annotated
Solution Guide
, available for a small fee from
t Les solutions d'exercices sélectionnés peuvent être trouvées dans le document électronique The Thinking in Java Annotated Solution Guide, disponible pour un faible coût sur www.BruceEckel.com.
t t t
  1.       Prove that the fields in
    an interface are implicitly static and
  2.     Create
    an interface containing three methods, in its own package.
    Implement the interface in a different
  3.   Prove
    that all the methods in an interface are automatically
  4.    In
    c07:Sandwich.java, create an interface called FastFood (with
    appropriate methods) and change Sandwich so that it also implements
  5. Create
    three interfaces, each with two methods. Inherit a new interface
    from the three, adding a new method. Create a class by implementing the new
    interface and also inheriting from a concrete class. Now write four
    methods, each of which takes one of the four interfaces as an argument.
    In main( ), create an object of your class and pass it to each of
    the methods.
  6.      Modify
    Exercise 5 by creating an abstract class and inheriting that into the
  7.      Modify
    Music5.java by adding a Playable interface. Remove the
    play( ) declaration from Instrument. Add Playable to
    the derived classes by including it in the implements list. Change
    tune( ) so that it takes a Playable instead of an
  8.      Change
    Exercise 6 in Chapter 7 so that Rodent is an
  9.       In
    Adventure.java, add an interface called CanClimb, following
    the form of the other
  10.       Write a
    program that imports and uses
  11.     Following
    the example given in Month2.java, create an enumeration of days of the
  12.       Create an
    interface with at least one method, in its own package. Create a class in
    a separate package. Add a protected inner class that implements the
    interface. In a third package, inherit from your class and, inside a
    method, return an object of the protected inner class, upcasting to the
    interface during the
  13.     Create an
    interface with at least one method, and implement that interface
    by defining an inner class within a method, which returns a reference to your
  14.       Repeat
    Exercise 13 but define the inner class within a scope within a
  15.     Repeat
    Exercise 13 using an anonymous inner
  16.      Create a
    private inner class that implements a public interface.
    Write a method that returns a reference to an instance of the private
    inner class, upcast to the interface. Show that the inner class is
    completely hidden by trying to downcast to
  17.   Create a class
    with a nondefault constructor and no default constructor. Create a second class
    that has a method which returns a reference to the first class. Create the
    object to return by making an anonymous inner class that inherits from the first
  18.      Create a
    class with a private field and a private method. Create an inner
    class with a method that modifies the outer class field and calls the outer
    class method. In a second outer class method, create an object of the inner
    class and call it’s method, then show the effect on the outer class
  19.     Repeat
    Exercise 18 using an anonymous inner
  20.      Create a
    class containing a static inner class. In main( ), create an
    instance of the inner
  21.      Create an
    interface containing a static inner class. Implement this
    interface and create an instance of the inner
  22.      Create a
    class containing an inner class that itself contains an inner class. Repeat this
    using static inner classes. Note the names of the .class files
    produced by the
  23.   Create a
    class with an inner class. In a separate class, make an instance of the inner
  24.      Create a
    class with an inner class that has a nondefault constructor. Create a second
    class with an inner class that inherits from the first inner
  25.      Repair the
    problem in
  26. Modify
    Sequence.java by adding a method getRSelector( ) that
    produces a different implementation of the Selector interface that
    moves backward through the sequence from the end to the
  27. Create an
    interface U with three methods. Create a class A with a
    method that produces a reference to a U by building an anonymous inner
    class. Create a second class B that contains an array of U.
    B should have one method that accepts and stores a reference to a
    U in the array, a second method that sets a reference in the array
    (specified by the method argument) to null and a third method that moves
    through the array and calls the methods in U. In main( ),
    create a group of A objects and a single B. Fill the B with
    U references produced by the A objects. Use the B to call
    back into all the A objects. Remove some of the U references from
    the B.
  28.     In
    GreenhouseControls.java, add Event inner classes that turn fans on
    and off.
  29.    Show that
    an inner class has access to the private elements of its outer class.
    Determine whether the reverse is true.

  1. Prouvez que les champs d'une interface sont implicitement static et final.
  2. Créez une interface contenant trois méthodes, dans son propre package. Implémentez cette interface dans un package différent.
  3. Prouvez que toutes les méthodes d'une interface sont automatiquement public.
  4. Dans c07:Sandwich.java, créez une interface appelée FastFood (avec les méthodes appropriées) et changez Sandwich afin qu'il implémente FastFood.
  5. Créez trois interfaces, chacune avec deux méthodes. Créez une nouvelle interface héritant des trois, en ajoutant une nouvelle méthode. Créez une classe implémentant la nouvelle interface et héritant déjà d'une classe concrète. Ecrivez maintenant quatre méthodes, chacune d'entre elles prenant l'une des quatre interfaces en argument. Dans main(), créez un objet de votre classe et passez-le à chacune des méthodes.
  6. Modifiez l'exercice 5 en créant une classe abstract et en la dérivant dans la dernière classe.
  7. Modifiez Music5.java en ajoutant une interfacePlayable. Enlevez la déclaration de play() d'Instrument. Ajoutez Playable aux classes dérivées en l'incluant dans la liste implements. Changez tune() afin qu'il accepte un Playable au lieu d'un Instrument.
  8. Changez l'exercice 6 du Chapitre 7 afin que Rodent soit une interface.
  9. Dans Adventure.java, ajoutez une interface appelée CanClimb respectant la forme des autres interfaces.
  10. Ecrivez un programme qui importe et utilise Month2.java.
  11. En suivant l'exemple donné dans Month2.java, créez une énumération des jours de la semaine.
  12. Créez une interface dans son propre package contenant au moins une méthode. Créez une classe dans un package séparé. Ajoutez une classe interne protected qui implémente l'interface. Dans un troisième package, dérivez votre classe, et dans une méthode renvoyez un objet de la classe interne protected, en le transtypant en interface durant le retour.
  13. Créez une interface contenant au moins une méthode, et implémentez cette interface en définissant une classe interne à l'intérieur d'une méthode, qui renvoie une référence sur votre interface.
  14. Répétez l'exercice 13 mais définissez la classe interne à l'intérieur d'une portée à l'intérieur de la méthode.
  15. Répétez l'exercice 13 en utilisant une classe interne anonyme.
  16. Créez une classe interne private qui implémente une interface public. Ecrivez une méthode qui renvoie une référence sur une instance de la classe interne private, transtypée en interface. Montrez que la classe interne est complètement cachée en essayant de la transtyper à nouveau.
  17. Créez une classe avec un constructeur autre que celui par défaut et sans constructeur par défaut. Créez une seconde classe disposant d'une méthode qui renvoie une référence à la première classe. Créez un objet à renvoyer en créant une classe interne anonyme dérivée de la première classe.
  18. Créez une classe avec un champ private et une méthode private. Créez une classe interne avec une méthode qui modifie le champ de la classe externe et appelle la méthode de la classe externe. Dans une seconde méthode de la classe externe, créez un objet de la classe interne et appelez sa méthode ; montrez alors l'effet sur l'objet de la classe externe.
  19. Répétez l'exercice 18 en utilisant une classe interne anonyme.
  20. Créez une classe contenant une classe interne static. Dans main(), créez une instance de la classe interne.
  21. Créez une interface contenant une classe interne static. Implémentez cette interface et créez une instance de la classe interne.
  22. Créez une classe contenant une classe interne contenant elle-même une classe interne. Répétez ce schéma en utilisant des classes internes static. Notez les noms des fichiers .class produits par le compilateur.
  23. Créez une classe avec une classe interne. Dans une classe séparée, créez une instance de la classe interne.
  24. Créez une classe avec une classe interne disposant d'un constructeur autre que celui par défaut. Créez une seconde classe avec une classe interne héritant de la première classe interne.
  25. Corrigez le problème dans WindError.java.
  26. Modifiez Sequence.java en ajoutant une méthode getRSelector() qui produise une implémentation différente de l'interface Selector afin de parcourir la séquence en ordre inverse, de la fin vers le début.
  27. Créez une interface U contenant trois méthodes. Créez une classe A avec une méthode qui produise une référence sur un U en construisant une classe interne anonyme. Créez une seconde classe B qui contienne un tableau de U. B doit avoir une méthode qui accepte et stocke une référence sur un U dans le tableau, une deuxième méthode qui positionne une référence (spécifiée par un argument de la méthode) dans le tableau à null, et une troisième méthode qui se déplace dans le tableau et appelle les méthodes de l'objet U. Dans main(), créez un groupe d'objets A et un objet B. Remplissez l'objet B avec les références U produites par les objets A. Utilisez B pour revenir dans les objets A. Enlevez certaines des références U de B.
  28. Dans GreenhouseControls.java, ajoutez des classes internes Event qui contrôlent des ventilateurs.
  29. Montrez qu'une classe interne peut accéder aux éléments private de sa classe externe. Déterminez si l'inverse est vrai.
t t t
This approach was inspired by an e-mail from Rich Hoffarth.
t [38]Cette approche m'a été inspirée par un e-mail de Rich Hoffarth.
t t t
Thanks to Martin Danner for asking this question during a
t [39]Merci à Martin Danner pour avoir posé cette question lors d'un séminaire.
t t t
This is very different from the design of nested classes in C++, which is
simply a name-hiding mechanism. There is no link to an enclosing object and no
implied permissions in C++.
t [40]Ceci est très différent du concept des classes imbriquées en C++, qui est simplement un mécanisme de camouflage de noms. Il n'y a aucun lien avec l'objet externe et aucune permission implicite en C++.
t t t
Thanks again to Martin Danner.
t [41]Merci encore à Martin Danner.
t t t
On the other hand, ‘$’ is a meta-character to the Unix shell and so
you’ll sometimes have trouble when listing the .class files. This
is a bit strange coming from Sun, a Unix-based company. My guess is that they
weren’t considering this issue, but instead thought you’d naturally
focus on the source-code files.
t [42]Attention cependant, '$' est un méta-caractère pour les shells unix et vous pourrez parfois rencontrer des difficultés en listant les fichiers .class. Ceci peut paraître bizarre de la part de Sun, une entreprise résolument tournée vers unix. Je pense qu'ils n'ont pas pris en compte ce problème car ils pensaient que l'attention se porterait surtout sur les fichiers sources.
t t t
For some reason this has always been a pleasing problem for me to solve; it came
from my earlier book C++ Inside & Out, but Java allows a much more
elegant solution.

     [ Previous Chapter ]
    [ Short TOC ]
    [ Table of Contents ]
    [ Index ]
     [ Next Chapter ]
Last Update:04/24/2000
t [43]Pour je ne sais quelle raison, ce problème m'a toujours semblé plaisant ; il vient de mon livre précédent C++ Inside & Out, mais Java offre une solution bien plus élégante.
t t t
t t t
t t
t t t
Sommaire Le site de Bruce Eckel