 |
 |
8) Interfaces et classes internes |
|
 |
|
Texte original |
 |
Traducteur : Jérome QUELIN |
|
 |
///
|
Ce chapitre contient 6 pages
1
2
3
4
5
6
|
|
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
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.
|
 |
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.
|
 |
 |
 |
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.
|
 |
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.
|
 |
 |
 |
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.
|
 |
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.
|
 |
 |
 |
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. |
 |
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.
|
 |
 |
 |
Summary
|
 |
Résumé
|
 |
 |
 |
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 accessible.
|
 |
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.
|
 |
 |
 |
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.
|
 |
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.
|
 |
 |
 |
Exercises
|
 |
Exercices
|
 |
 |
 |
Solutions to selected exercises can be found in the electronic document The Thinking in Java Annotated Solution Guide, available for a small fee from www.BruceEckel.com.
|
 |
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.
|
 |
 |
 |
- Prove that the fields in
an interface are implicitly static and final. - Create
an interface containing three methods, in its own package. Implement the interface in a different package. - Prove
that all the methods in an interface are automatically public. - In
c07:Sandwich.java, create an interface called FastFood (with appropriate methods) and change Sandwich so that it also implements FastFood. - 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. - Modify
Exercise 5 by creating an abstract class and inheriting that into the derived class. - 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 Instrument. - Change
Exercise 6 in Chapter 7 so that Rodent is an interface. - In
Adventure.java, add an interface called CanClimb, following the form of the other interfaces. - Write a
program that imports and uses Month2.java. - Following
the example given in Month2.java, create an enumeration of days of the week. - 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 return. - 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 interface. - Repeat
Exercise 13 but define the inner class within a scope within a method. - Repeat
Exercise 13 using an anonymous inner class. - 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 it. - 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 class. - 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 object. - Repeat
Exercise 18 using an anonymous inner class. - Create a
class containing a static inner class. In main( ), create an instance of the inner class. - Create an
interface containing a static inner class. Implement this interface and create an instance of the inner class. - 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 compiler. - Create a
class with an inner class. In a separate class, make an instance of the inner class. - 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 class. - Repair the
problem in WindError.java. - 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 beginning. - 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. - In
GreenhouseControls.java, add Event inner classes that turn fans on and off. - Show that
an inner class has access to the private elements of its outer class. Determine whether the reverse is true.
|
 |
- Prouvez que les champs d'une interface sont implicitement
static et final.
- Créez une interface contenant trois méthodes, dans son
propre package. Implémentez cette interface dans un package
différent.
- Prouvez que toutes les méthodes d'une interface sont
automatiquement public.
- 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.
- 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.
- Modifiez l'exercice 5 en créant une classe abstract et en
la dérivant dans la dernière classe.
- 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.
- Changez l'exercice 6 du Chapitre 7 afin que Rodent soit
une interface.
- Dans Adventure.java, ajoutez une
interface appelée CanClimb respectant la forme des autres
interfaces.
- Ecrivez un programme qui importe et utilise
Month2.java.
- En suivant l'exemple donné dans Month2.java, créez une
énumération des jours de la semaine.
- 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.
- 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.
- 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.
- Répétez l'exercice 13 en utilisant une classe interne anonyme.
- 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.
- 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.
- 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.
- Répétez l'exercice 18 en utilisant une classe interne anonyme.
- Créez une classe contenant une classe interne static.
Dans main(), créez une instance de la classe interne.
- Créez une interface contenant une classe interne
static. Implémentez cette interface et créez une instance de la
classe interne.
- 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.
- Créez une classe avec une classe interne. Dans une classe séparée, créez
une instance de la classe interne.
- 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.
- Corrigez le problème dans WindError.java.
- 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.
- 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.
- Dans GreenhouseControls.java, ajoutez des classes
internes Event qui contrôlent des ventilateurs.
- Montrez qu'une classe interne peut accéder aux éléments
private de sa classe externe. Déterminez si l'inverse est vrai.
|
 |
 |
 |
[38] This approach was inspired by an e-mail from Rich Hoffarth.
|
 |
[38]Cette approche m'a été inspirée par un
e-mail de Rich Hoffarth.
|
 |
 |
 |
[39] Thanks to Martin Danner for asking this question during a seminar.
|
 |
[39]Merci à Martin Danner pour avoir posé
cette question lors d'un séminaire.
|
 |
 |
 |
[40] 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++.
|
 |
[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++.
|
 |
 |
 |
[41] Thanks again to Martin Danner.
|
 |
[41]Merci encore à Martin
Danner.
|
 |
 |
 |
[42] 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.
|
 |
[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.
|
 |
 |
 |
[43] 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
|
 |
[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.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |