t
t
t
t
t t   12) Identification dynamique de type
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 carre6) 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 12) 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 : Daniel Le Berre
t
t
///
Ce chapitre contient 3 pages
1 2 3
    
t t t
t t t
t
t t t
Another compelling motivation for discovering class information at run-time is to provide the ability to create and execute objects on remote platforms across a network. This is called Remote Method Invocation (RMI) and it allows a Java program to have objects distributed across many machines. This distribution can happen for a number of reasons: for example, perhaps you’re doing a computation-intensive task and you want to break it up and put pieces on machines that are idle in order to speed things up. In some situations you might want to place code that handles particular types of tasks (e.g., “Business Rules” in a multitier client/server architecture) on a particular machine, so that machine becomes a common repository describing those actions and it can be easily changed to affect everyone in the system. (This is an interesting development, since the machine exists solely to make software changes easy!) Along these lines, distributed computing also supports specialized hardware that might be good at a particular task—matrix inversions, for example—but inappropriate or too expensive for general purpose programming.
t Une autre motivation pour découvrir dynamiquement des informations sur une classe est de permettre la création et l'exécution d'objets sur des plates forme distantes via un réseau. Ceci est appelé Remote Method Invocation (RMI) et permet à un programme Java d'avoir des objets répartis sur plusieurs machines. Cette répartition peut survenir pour diverses raisons : par exemple, vous effectuez une tâche coûteuse en calcul et vous voulez la dissocier pour utiliser certains morceaux sur des machines libres afin d'accélérer les choses. Dans certaines situations vous aimeriez placer le code d'un certain type de tâches (par exemple « Business Rules » dans une architecture  client/serveur multitiers ??????) sur une machine particulière, afin que celle-ci devienne le dépositaire unique de ces tâches, pouvant être facilement modifié pour changer tout le système (c'est un développement intéressant puisque la machine existe uniquement pour faciliter les changements logiciels !). Enfin, le calcul distribué supporte aussi des architectures spécialisées qui peuvent être appropriées à des tâches spécifiques- l'inversion de matrices, par exemple- mais inappropriées ou trop chères pour la programmation classique.
t t t
The class Class (described previously in this chapter) supports the concept of reflection, and there’s an additional library, java.lang.reflect, with classes Field, Method, and Constructor (each of which implement the Member interface). Objects of these types are created by the JVM at run-time to represent the corresponding member in the unknown class. You can then use the Constructors to create new objects, the get( ) and set( ) methods to read and modify the fields associated with Field objects, and the invoke( ) method to call a method associated with a Method object. In addition, you can call the convenience methods getFields( ), getMethods( ), getConstructors( ), etc., to return arrays of the objects representing the fields, methods, and constructors. (You can find out more by looking up the class Class in your online documentation.) Thus, the class information for anonymous objects can be completely determined at run-time, and nothing need be known at compile-time.
t La classe Class (décrite précédemment dans ce chapitre) supporte le concept de réflexion, et une bibliothèque additionnelle, java.lang.reflect, contenant les classes FieldMethod, et Constructor (chacune implémentant l'interface Member). Les objets de ce type sont créés dynamiquement par la JVM pour représenter les membres correspondants d'une classe inconnue. On peut alors utiliser les constructeurs pour créer de nouveaux objets, les méthodes get() et set() pour lire et modifier les champs associés à des objets Field, et la méthode invoke() pour appeler une méthode associée à un objet Method. De plus, on peut utiliser les méthodes très pratiques getFields(), getMethods(), getConstructors(), etc. retournant un tableau représentant respectivement des champs, méthodes et constructeurs (pour en savoir plus, jetez un oeil à la documentation en ligne de la classe Class). Ainsi, l'information sur la classe d'objets inconnus peut être totalement déterminée dynamiquement, sans rien en savoir à la compilation.
t t t
It’s important to realize that there’s nothing magic about reflection. When you’re using reflection to interact with an object of an unknown type, the JVM will simply look at the object and see that it belongs to a particular class (just like ordinary RTTI) but then, before it can do anything else, the Class object must be loaded. Thus, the .class file for that particular type must still be available to the JVM, either on the local machine or across the network. So the true difference between RTTI and reflection is that with RTTI, the compiler opens and examines the .class file at compile-time. Put another way, you can call all the methods of an object in the “normal” way. With reflection, the .class file is unavailable at compile-time; it is opened and examined by the run-time environment.
t Il est important de noter qu'il n'y a rien de magique dans la réflexion. Quand vous utilisez la réflexion pour interagir avec des objets de type inconnu, la JVM va simplement regarder l'objet et voir qu'il appartient à une classe particulière (comme une RTTI ordinaire) mais, avant toute autre chose, l'objet Class doit être chargé. Le fichier .class pour ce type particulier doit donc être disponible pour la JVM, soit localement sur la machine ou via le réseau. La vraie différence entre le RTTI et la réflexion est donc qu'avec le RTTI, le compilateur ouvre et examine le fichier .class à la compilation. Dit autrement, vous pouvez appeler toutes les méthodes d'un objet “normalement”. Avec la réflexion, le fichier .class n'est pas disponible à la compilation ; il est ouvert et examiné à l'exécution.
t t t

A class method extractor

t

Un extracteur de méthodes de classe

t t t
You’ll rarely need to use the reflection tools directly; they’re in the language to support other Java features, such as object serialization (Chapter 11), JavaBeans (Chapter 13), and RMI (Chapter 15). However, there are times when it’s quite useful to be able to dynamically extract information about a class. One extremely useful tool is a class method extractor. As mentioned before, looking at a class definition source code or online documentation shows only the methods that are defined or overridden within that class definition. But there could be dozens more available to you that have come from base classes. To locate these is both tedious and time consuming[60]. Fortunately, reflection provides a way to write a simple tool that will automatically show you the entire interface. Here’s the way it works:
t Vous aurez rarement besoin d'utiliser directement les outils de réflexion ; ils sont utilisés pour supporter d'autres caractéristiques de Java, telles que la sérialisation (Chapitre 11), JavaBeans (Chapitre 13) et RMI (Chapitre 15). Néanmoins, il est quelquefois utile d'extraire dynamiquement des informations sur une classe. Un outil très utile est un extracteur de méthode de classe. Comme mentionné précédemment, chercher le code définissant une classe ou sa documentation en ligne montre uniquement les méthodes définies ou redéfinies dans cette définition de classe. Mais il peut y en avoir des douzaines d'autre qui proviennent des classes de base. Les retrouver est fastidieux et long  [60]. Heureusement, la réflexion fournit un moyen d'écrire un outil simple qui va automatiquement montrer l'interface entière. Voici comment il fonctionne :
t t t
//: c12:ShowMethods.java // Using reflection to show all the methods of // a class, even if the methods are defined in // the base class. import java.lang.reflect.*; public class ShowMethods { static final String usage = "usage: \n" + "ShowMethods qualified.class.name\n" + "To show all methods in class or: \n" + "ShowMethods qualified.class.name word\n" + "To search for methods involving 'word'"; public static void main(String[] args) { if(args.length < 1) { System.out.println(usage); System.exit(0); } try { Class c = Class.forName(args[0]); Method[] m = c.getMethods(); Constructor[] ctor = c.getConstructors(); if(args.length == 1) { for (int i = 0; i < m.length; i++) System.out.println(m[i]); for (int i = 0; i < ctor.length; i++) System.out.println(ctor[i]); } else { for (int i = 0; i < m.length; i++) if(m[i].toString() .indexOf(args[1])!= -1) System.out.println(m[i]); for (int i = 0; i < ctor.length; i++) if(ctor[i].toString() .indexOf(args[1])!= -1) System.out.println(ctor[i]); } } catch(ClassNotFoundException e) { System.err.println("No such class: " + e); } } } ///:~ t
//: c12:ShowMethods.java
// Utiliser la réflexion pour montrer toutes les méthodes
// d'une classe, même si celles ci sont définies dans la
// classe de base.
import java.lang.reflect.*;

public class ShowMethods {
  static final String usage =    "usage: \n" +
    "ShowMethods qualified.class.name\n" +
    "Pour montrer toutes les méthodes or: \n" +
    "ShowMethods qualified.class.name word\n" +
    "Pour rechercher les méthodes contenant 'word'";
  public static void main(String[] args) {
    if(args.length < 1) {
      System.out.println(usage);
      System.exit(0);
    }
    try {
      Class c = Class.forName(args[0]);
      Method[] m = c.getMethods();
      Constructor[] ctor = c.getConstructors();
      if(args.length == 1) {
        for (int i = 0; i < m.length; i++)
          System.out.println(m[i]);
        for (int i = 0; i < ctor.length; i++)
          System.out.println(ctor[i]);
      } else {
        for (int i = 0; i < m.length; i++)
          if(m[i].toString()
             .indexOf(args[1])!= -1)
            System.out.println(m[i]);
        for (int i = 0; i < ctor.length; i++)
          if(ctor[i].toString()
             .indexOf(args[1])!= -1)
          System.out.println(ctor[i]);
      }
    } catch(ClassNotFoundException e) {
      System.err.println("Classe non trouvée : " + e);
    }
  }
} ///:~
t t t
The Class methods getMethods( ) and getConstructors( ) return an array of Method and Constructor, respectively. Each of these classes has further methods to dissect the names, arguments, and return values of the methods they represent. But you can also just use toString( ), as is done here, to produce a String with the entire method signature. The rest of the code is just for extracting command line information, determining if a particular signature matches with your target string (using indexOf( )), and printing the results.
t Les méthodes de Class getMethods() et getConstructors() retournent respectivement un tableau de Method et Constructor. Chacune de ces classes a de plus des méthodes pour obtenir les noms, arguments et valeur retournée des méthodes qu'elles représentent. Mais vous pouvez aussi utiliser simplement toString(), comme ici, pour produire une chaîne de caractères avec la signature complète de la méthode. Le reste du code sert juste pour l'extraction des informations de la ligne de commande, déterminer si une signature particulière correspond à votre chaîne cible (en utilisant indexOf()), et afficher le résultat.
t t t
This shows reflection in action, since the result produced by Class.forName( ) cannot be known at compile-time, and therefore all the method signature information is being extracted at run-time. If you investigate your online documentation on reflection, you’ll see that there is enough support to actually set up and make a method call on an object that’s totally unknown at compile-time (there will be examples of this later in this book). Again, this is something you may never need to do yourself—the support is there for RMI and so a programming environment can manipulate JavaBeans—but it’s interesting.
t Ceci montre la réflexion en action, puisque le résultat de Class.forName() ne peut pas être connu à la compilation, donc toutes les informations sur la signature des méthodes est extraite à l'exécution. Si vous étudiez la documentation en ligne sur la réflexion, vous verrez qu'il est possible de créér et d'appeler une méthode d'un objet qui était totalement inconnu lors de la compilation (nous verrons des exemples plus loin dans ce livre). Encore une fois, c'est quelque chose dont vous n'aurez peut être jamais besoin de faire vous même- le support est là pour le RMI et la programmation par JavaBeans- mais il est intéressant.
t t t
An interesting experiment is to run
t Une expérience intéressante est de lancer :
t t t
java ShowMethods ShowMethods t
java ShowMethods ShowMethods
t t t
This produces a listing that includes a public default constructor, even though you can see from the code that no constructor was defined. The constructor you see is the one that’s automatically synthesized by the compiler. If you then make ShowMethods a non-public class (that is, friendly), the synthesized default constructor no longer shows up in the output. The synthesized default constructor is automatically given the same access as the class.
t Ceci produit une liste qui inclut un constructeur par défaut public, bien que vous puissiez voir à partir du code source qu'aucun constructeur n'ait été défini. Le constructeur que vous voyez est celui qui est automatiquement généré par le compilateur. Si vous définissez maintenant ShowMethods comme une classe non public (par exemple, amie), le constructeur par défaut n'apparaît plus dans la liste. Le constructeur pas défaut généré a automatiquement le même accès que la classe.
t t t
The output for ShowMethods is still a little tedious. For example, here’s a portion of the output produced by invoking java ShowMethods java.lang.String:
t L'affichage de ShowMethods est toujours un peu ennuyeuse. Par exemple, voici une portion de l'affichage produit en invoquant  java ShowMethods java.lang.String :
t t t
public boolean java.lang.String.startsWith(java.lang.String,int) public boolean java.lang.String.startsWith(java.lang.String) public boolean java.lang.String.endsWith(java.lang.String) t
public boolean
  java.lang.String.startsWith(java.lang.String,int)
public boolean
  java.lang.String.startsWith(java.lang.String)
public boolean
  java.lang.String.endsWith(java.lang.String)
t t t
It would be even nicer if the qualifiers like java.lang could be stripped off. The StreamTokenizer class introduced in the previous chapter can help create a tool to solve this problem:
t Il serait préférable que les préfixes comme java.lang puissent être éliminés. La classe StreamTokenizer introduite dans le chapitre précédent peut nous aider à créer un outil résolvant ce problème :
t t t
//: com:bruceeckel:util:StripQualifiers.java package com.bruceeckel.util; import java.io.*; public class StripQualifiers { private StreamTokenizer st; public StripQualifiers(String qualified) { st = new StreamTokenizer( new StringReader(qualified)); st.ordinaryChar(' '); // Keep the spaces } public String getNext() { String s = null; try { int token = st.nextToken(); if(token != StreamTokenizer.TT_EOF) { switch(st.ttype) { case StreamTokenizer.TT_EOL: s = null; break; case StreamTokenizer.TT_NUMBER: s = Double.toString(st.nval); break; case StreamTokenizer.TT_WORD: s = new String(st.sval); break; default: // single character in ttype s = String.valueOf((char)st.ttype); } } } catch(IOException e) { System.err.println("Error fetching token"); } return s; } public static String strip(String qualified) { StripQualifiers sq = new StripQualifiers(qualified); String s = "", si; while((si = sq.getNext()) != null) { int lastDot = si.lastIndexOf('.'); if(lastDot != -1) si = si.substring(lastDot + 1); s += si; } return s; } } ///:~ t
//: com:bruceeckel:util:StripQualifiers.java
package com.bruceeckel.util;
import java.io.*;

public class StripQualifiers {
  private StreamTokenizer st;
  public StripQualifiers(String qualified) {
    st = new StreamTokenizer(
      new StringReader(qualified));
    st.ordinaryChar(' '); // garde les espaces
  }
  public String getNext() {
    String s = null;
    try {
      int token = st.nextToken();
      if(token != StreamTokenizer.TT_EOF) {
        switch(st.ttype) {
          case StreamTokenizer.TT_EOL:
            s = null;
            break;
          case StreamTokenizer.TT_NUMBER:
            s = Double.toString(st.nval);
            break;
          case StreamTokenizer.TT_WORD:
            s = new String(st.sval);
            break;
          default: //il y a un seul caractère dans ttype
            s = String.valueOf((char)st.ttype);
        }
      }
    } catch(IOException e) {
      System.err.println("Erreur recherche token");
    }
    return s;
  }
  public static String strip(String qualified) {
    StripQualifiers sq =
      new StripQualifiers(qualified);
    String s = "", si;
    while((si = sq.getNext()) != null) {
      int lastDot = si.lastIndexOf('.');
      if(lastDot != -1)
        si = si.substring(lastDot + 1);
      s += si;
    }
    return s;
  }
} ///:~
t t t
To facilitate reuse, this class is placed in com.bruceeckel.util. As you can see, this uses the StreamTokenizer and String manipulation to do its work.
t Pour faciliter sa réutilisation, cette classe est placée dans com.bruceeckel.util. Comme vous pouvez le voir, elle utilise la classe StreamTokenizer et la manipulation des String pour effectuer son travail.
t t t
The new version of the program uses the above class to clean up the output:
t La nouvelle version du programme utilise la classe ci-dessus pour clarifier le résultat :
t t t
//: c12:ShowMethodsClean.java // ShowMethods with the qualifiers stripped // to make the results easier to read. import java.lang.reflect.*; import com.bruceeckel.util.*; public class ShowMethodsClean { static final String usage = "usage: \n" + "ShowMethodsClean qualified.class.name\n" + "To show all methods in class or: \n" + "ShowMethodsClean qualif.class.name word\n" + "To search for methods involving 'word'"; public static void main(String[] args) { if(args.length < 1) { System.out.println(usage); System.exit(0); } try { Class c = Class.forName(args[0]); Method[] m = c.getMethods(); Constructor[] ctor = c.getConstructors(); // Convert to an array of cleaned Strings: String[] n = new String[m.length + ctor.length]; for(int i = 0; i < m.length; i++) { String s = m[i].toString(); n[i] = StripQualifiers.strip(s); } for(int i = 0; i < ctor.length; i++) { String s = ctor[i].toString(); n[i + m.length] = StripQualifiers.strip(s); } if(args.length == 1) for (int i = 0; i < n.length; i++) System.out.println(n[i]); else for (int i = 0; i < n.length; i++) if(n[i].indexOf(args[1])!= -1) System.out.println(n[i]); } catch(ClassNotFoundException e) { System.err.println("No such class: " + e); } } } ///:~ t
//: c12:ShowMethodsClean.java
// ShowMethods avec élimination des préfixes
// pour faciliter la lecture du résultat.
import java.lang.reflect.*;
import com.bruceeckel.util.*;

public class ShowMethodsClean {
  static final String usage =    "usage: \n" +
    "ShowMethodsClean qualified.class.name\n" +
    "Pour montrer toutes les méthodes or: \n" +
    "ShowMethodsClean qualified.class.name word\n" +
    "Pour rechercher les méthodes contenant 'word'";

  public static void main(String[] args) {
    if(args.length < 1) {
      System.out.println(usage);
      System.exit(0);
    }
    try {
      Class c = Class.forName(args[0]);
      Method[] m = c.getMethods();
      Constructor[] ctor = c.getConstructors();
      // Conversion en un tableau de chaînes simplifiées :
      String[] n =
        new String[m.length + ctor.length];
      for(int i = 0; i < m.length; i++) {
        String s = m[i].toString();
        n[i] = StripQualifiers.strip(s);
      }
      for(int i = 0; i < ctor.length; i++) {
        String s = ctor[i].toString();
        n[i + m.length] =
          StripQualifiers.strip(s);
      }
      if(args.length == 1)
        for (int i = 0; i < n.length; i++)
          System.out.println(n[i]);
      else
              for (int i = 0; i < n.length; i++)
          if(n[i].indexOf(args[1])!= -1)
            System.out.println(n[i]);
    } catch(ClassNotFoundException e) {
      System.err.println("Classe non trouvée : " + e);
    }
  }
} ///:~
t t t
The class ShowMethodsClean is quite similar to the previous ShowMethods, except that it takes the arrays of Method and Constructor and converts them into a single array of String. Each of these String objects is then passed through StripQualifiers.Strip( ) to remove all the method qualification.
t La classe ShowMethodsClean est semblable à la classe ShowMethods, excepté qu'elle transforme les tableaux de Method et Constructor en un seul tableau de String. Chaque String est ensuite appliquée à StripQualifiers.strip() pour enlever les préfixes des méthodes.
t t t
This tool can be a real time-saver while you’re programming, when you can’t remember if a class has a particular method and you don’t want to go walking through the class hierarchy in the online documentation, or if you don’t know whether that class can do anything with, for example, Color objects.
t Cet outil peut réellement vous faire gagner du temps lorsque vous programmez, quand vous ne vous souvenez pas si une classe a une méthode particulière et que vous ne voulez pas explorer toute sa hiérarchie dans la documentation en ligne, ou si vous ne savez pas si cette classe peut faire quelque chose avec, par exemple, un objet Color.
t t t
Chapter 13 contains a GUI version of this program (customized to extract information for Swing components) so you can leave it running while you’re writing code, to allow quick lookups.
t Le chapitre 13 contient une version graphique de ce programme (adapté pour extraire des informations sur les composants Swing) que vous pouvez laisser tourner pendant que vous écrivez votre code, pour des recherches rapides.
t t t

Summary

t

Résumé

t t t
RTTI allows you to discover type information from an anonymous base-class reference. Thus, it’s ripe for misuse by the novice since it might make sense before polymorphic method calls do. For many people coming from a procedural background, it’s difficult not to organize their programs into sets of switch statements. They could accomplish this with RTTI and thus lose the important value of polymorphism in code development and maintenance. The intent of Java is that you use polymorphic method calls throughout your code, and you use RTTI only when you must.
t L'identification dynamique de type (RTTI) permet de découvrir des informations de type à partir d'une référence sur une classe de base inconnue. [je n'arrive pas à traduire cette phrase: Thus, it’s ripe for misuse by the novice since it might make sense before polymorphic method calls do. Prop1:Ainsi, il mûrit pour sa mauvaise utilisation par le novice puisque il pourrait être utilise de le faire avant un appel de méthode polymorphique. Prop2 (JQ): Malheureusement ces informations peuvent conduire le novice à négliger les concepts du polymorphisme, puisqu'elles sont plus faciles à appréhender.] Pour beaucoup de gens habitués à la programmation procédurale, il est difficile de ne pas organiser leurs programmes en ensembles d'expressions switch. Ils pourraient faire la même chose avec le RTTI et perdraient ainsi l'importante valeur du polymorphisme dans le développement et la maintenance du code. L'intention de Java est de vous faire utiliser des appels de méthodes polymorphiques dans votre code, et de vous faire utiliser le RTTI uniquement lorsque c'est nécessaire.
t t t
However, using polymorphic method calls as they are intended requires that you have control of the base-class definition because at some point in the extension of your program you might discover that the base class doesn’t include the method you need. If the base class comes from a library or is otherwise controlled by someone else, a solution to the problem is RTTI: You can inherit a new type and add your extra method. Elsewhere in the code you can detect your particular type and call that special method. This doesn’t destroy the polymorphism and extensibility of the program because adding a new type will not require you to hunt for switch statements in your program. However, when you add new code in your main body that requires your new feature, you must use RTTI to detect your particular type.
t Néanmoins, utiliser des appels de méthodes polymorphiques nécessite que vous ayez le contrôle de la définition des classes de base car il est possible que lors du développement de votre programme vous découvriez que la classe de base ne contient pas une méthode dans vous avez besoin. Si la classe de base provient d'une bibliothèque ou si elle est contrôlée par quelqu'un d'autre, une solution à ce problème est le RTTI : vous pouvez créer un nouveau type  héritant de cette classe auquel vous ajoutez la méthode manquante. Ailleurs dans le code, vous détectez ce type particulier et appelez cette méthode spécifique. Ceci ne détruit ni le polymorphisme ni l'extensibilité du programme car ajouter un nouveau type ne vous oblige pas à chasser les expressions switch dans votre programme. Cependant, lorsque vous ajoutez du code qui requiert cette nouvelle fonctionnalité dans votre programme principal, vous devez utiliser le RTTI pour détecter ce type particulier.
t t t
Putting a feature in a base class might mean that, for the benefit of one particular class, all of the other classes derived from that base require some meaningless stub of a method. This makes the interface less clear and annoys those who must override abstract methods when they derive from that base class. For example, consider a class hierarchy representing musical instruments. Suppose you wanted to clear the spit valves of all the appropriate instruments in your orchestra. One option is to put a clearSpitValve( ) method in the base class Instrument, but this is confusing because it implies that Percussion and Electronic instruments also have spit valves. RTTI provides a much more reasonable solution in this case because you can place the method in the specific class (Wind in this case), where it’s appropriate. However, a more appropriate solution is to put a prepareInstrument( ) method in the base class, but you might not see this when you’re first solving the problem and could mistakenly assume that you must use RTTI.
t Mettre la nouvelle caractéristique dans la classe de base peut signifier que, pour le bénéfice d'une classe particulière, toutes les autres classes dérivées de cette classe de base devront contenir des bouts de code inutiles de la méthode. Cela rend l'interface moins claire et ennuie celui qui doit redéfinir des méthodes abstraites dérivant de la classe de base. Supposez que vous désiriez nettoyer les becs? [spit valves] de tous les instruments à vent de votre orchestre. Une solution est de mettre une méthode nettoyerBec() dans la classe de base Instrument, mais c'est ennuyeux car cela implique que les instruments Electroniques et à Percussion ont aussi un bec. Le RTTI fournit une solution plus élégante dans ce cas car vous pouvez placer la méthode dans une classe spécifique (Vent dans notre cas), où elle est appropriée. Néanmoins, une solution encore meilleure est de mettre une méthode prepareInstrument() dans la classe de base, mais il se peut que vous ne la trouviez pas la première fois que vous ayez à résoudre le problème, et croyiez à tort que l'utilisation du RTTI est nécessaire.
t t t
Finally, RTTI will sometimes solve efficiency problems. If your code nicely uses polymorphism, but it turns out that one of your objects reacts to this general purpose code in a horribly inefficient way, you can pick out that type using RTTI and write case-specific code to improve the efficiency. Be wary, however, of programming for efficiency too soon. It’s a seductive trap. It’s best to get the program working first, then decide if it’s running fast enough, and only then should you attack efficiency issues—with a profiler.
t Enfin, le RTTI permettra parfois de résoudre des problèmes d'efficacité. Si votre code utilise le polymorphisme, mais qu'il s'avère que l'un de vos objets réagisse à ce code très général d'une manière particulièrement inefficace, vous pouvez reconnaître ce type en utilisant le RTTI et écrire un morceau de code spécifique pour améliorer son efficacité. Attention toutefois à programmer pour l'efficacité  trop tôt. C'est un piège séduisant. Il est préférable d'avoir un programme qui marche d'abord, et décider ensuite s'il est assez rapide, et seulement à ce moment là vous attaquer aux problèmes de performances — avec un profiler.
t t t

Exercises

t

Exercices

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 www.BruceEckel.com.
t Les solutions de certains exercices se trouvent dans le document électronique Guide des solutions annoté de Penser en Java, disponible à prix réduit depuis www.BruceEckel.com.
t t t
  1. Add Rhomboid to Shapes.java. Create a Rhomboid, upcast it to a Shape, then downcast it back to a Rhomboid. Try downcasting to a Circle and see what happens.
  2. Modify Exercise 1 so that it uses instanceof to check the type before performing the downcast.
  3. Modify Shapes.java so that it can “highlight” (set a flag) in all shapes of a particular type. The toString( ) method for each derived Shape should indicate whether that Shape is “highlighted.”
  4. Modify SweetShop.java so that each type of object creation is controlled by a command-line argument. That is, if your command line is “java SweetShop Candy,” then only the Candy object is created. Notice how you can control which Class objects are loaded via the command-line argument.
  5. Add a new type of Pet to PetCount3.java. Verify that it is created and counted correctly in main( ).
  6. Write a method that takes an object and recursively prints all the classes in that object’s hierarchy.
  7. Modify Exercise 6 so that it uses Class.getDeclaredFields( ) to also display information about the fields in a class.
  8. In ToyTest.java, comment out Toy’s default constructor and explain what happens.
  9. Incorporate a new kind of interface into ToyTest.java and verify that it is detected and displayed properly.
  10. Create a new type of container that uses a private ArrayList to hold the objects. Capture the type of the first object you put in it, and then allow the user to insert objects of only that type from then on.
  11. Write a program to determine whether an array of char is a primitive type or a true object.
  12. Implement clearSpitValve( ) as described in the summary.
  13. Implement the rotate(Shape) method described in this chapter, such that it checks to see if it is rotating a Circle (and, if so, doesn’t perform the operation).
  14. Modify Exercise 6 so that it uses reflection instead of RTTI.
  15. Modify Exercise 7 so that it uses reflection instead of RTTI.
  16. In ToyTest.java, use reflection to create a Toy object using the nondefault constructor.
  17. Look up the interface for java.lang.Class in the HTML Java documentation from java.sun.com. Write a program that takes the name of a class as a command-line argument, then uses the Class methods to dump all the information available for that class. Test your program with a standard library class and a class you create.
t
  1. Ajouter Rhomboïde àFormes.java. Créer un Rhomboïde, le transtyper en une Forme, ensuite le re-transtyper en un Rhomboïde. Essayer de le transtyper en un Cercle et voir ce qui se passe.
  2. Modifier l'exercice 1 afin d'utiliser instanceof pour vérifier le type avant d'effectuer le transtypage descendant.
  3. Modifier Formes.java afin que toutes les formes d'un type particulier puissent être mises en surbrillance (utiliser un drapeau). La méthode toString() pour chaque classe dérivée de Forme devra indiquer si cette Forme est mise en surbrillance ou pas.
  4. Modifier Confiseur.java afin que la création de chaque type d'objet soit contrôlée par la ligne de commande. Par exemple, si la ligne de commande est “java Confiseur Bonbon”, seul l'objet Bonbon sera créé. Noter comment vous pouvez contrôler quels objets Class sont chargés via la ligne de commande.
  5. Ajouter un nouveau type de Pet à PetCount3.java. Vérifier qu'il est correctement créé et compté dans la méthode main().
  6. Écrire une méthode qui prend un objet en paramètre et affiche récursivement tous les classes de sa hiérarchie.
  7. Modifier l'exercice 6 afin d'utiliser Class.getDeclaredFields() pour afficher aussi les informations sur les champs de chaque classe.
  8. Dans ToyTest.java, commenter le constructeur par défaut de Toy et expliquer ce qui arrive.
  9. Ajouter une nouvelle interface dans ToyTest.java et vérifier qu'elle est correctement détectée et affichée.
  10. Créer un nouveau type de conteneur qui utilise une private ArrayList pour stocker les objets. Déterminer le type du premier objet déposé, ne permettre ensuite à l'utilisateur que d'insérer des objets de ce type.
  11. Écrire un programme qui détermine si un tableau de char est un type primitif ou réellement un objet.
  12. Implanter nettoyerBec( ) comme décrit dans le résumé.
  13. Modifier l'exercice 6 afin d'utiliser la réflexion à la place du RTTI.
  14. Modifier l'exercice 7 afin d'utiliser la réflexion à la place du RTTI.
  15. Dans ToyTest.java, utiliser la réflexion pour créer un objet Toy en n'utilisant pas le constructeur par défaut.
  16. Étudier l'interface java.lang.Class dans la documentation HTML de Java à java.sun.com. Écrire un programme qui prend en paramètre le nom d'une classe via la ligne de commande, et utilise les méthodes de Class pour extraire toutes les informations disponibles pour cette classe. Tester le programme sur une classe de la bibliothèque standard et sur une des vôtres.
t t t
[60] Especially in the past. However, Sun has greatly improved its HTML Java documentation so that it’s easier to see base-class methods.
[ Previous Chapter ] [ Short TOC ] [ Table of Contents ] [ Index ] [ Next Chapter ]
Last Update:04/24/2000
t [60] Spécialement dans le passé. Néanmoins, Sun a grandement amélioré la documentation HTML de Java et il est maintenant plus aisé de voir les méthodes des classes de base.
t t t
t t t
t t
\\\
    
t t t
t
     
Sommaire Le site de Bruce Eckel