 |
 |
12) Identification dynamique de type |
|
 |
|
Texte original |
 |
Traducteur : Daniel LE BERRE |
|
 |
///
|
Ce chapitre contient 3 pages
1
2
3
|
|
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
There’s a rather narrow restriction
on instanceof: you can compare it to a named type only, and not to a
Class object. In the example above you might feel that it’s tedious
to write out all of those instanceof expressions, and you’re right.
But there is no way to cleverly automate instanceof by creating an
ArrayList of Class objects and comparing it to those instead (stay
tuned—you’ll see an alternative). This isn’t as great a
restriction as you might think, because you’ll eventually understand that
your design is probably flawed if you end up writing a lot of instanceof
expressions.
|
 |
Il existe cependant une limitation concernant instanceof :
un objet peut être comparé à un identifiant de type, pas à un objet Class. Dans
l'exemple précédent, vous pouvez trouver fastidieux d'écrire tous ces instanceof,
et vous avez raison. Mais il n'y a pas moyen d'automatiser intelligemment le
instanceof en créant un ArrayList d'objets Class
et en comparant l'objet à ces derniers (nous verrons plus loin une alternative). Vous pouvez penser
que ce n'est pas une très grande restriction, car vous finirez par comprendre que votre conception
est mauvaise si vous finissez par écrire un grand nombre de instanceof.
|
 |
 |
 |
Of course this example is
contrived—you’d probably put a static data member in each
type and increment it in the constructor to keep track of the counts. You would
do something like that if you had control of the source code for the
class and could change it. Since this is not always the case, RTTI can come in
handy.
|
 |
Bien sûr, cet exemple est imaginaire - vous utiliseriez probablement un
attribut de classe (static) pour chaque type que vous incrémenteriez dans le
constructeur pour mettre à jour les compteurs. Vous feriez cela si vous avez accès au code
source de ces classes et pouvez le modifier. Comme ce n'est pas toujours le cas, le RTTI est bien
pratique.
|
 |
 |
 |
Using class literals
|
 |
Utiliser les littéraux de classe
|
 |
 |
 |
It’s interesting to see how the
PetCount.java example can be rewritten using class
literals. The result is cleaner
in many ways:
|
 |
Il est intéressant de voir comment l'exemple précédent
PetCount.java peut être réécrit en utilisant les littéraux de classe. Le résultat
est plus satisfaisant sur bien des points :
|
 |
 |
 |
//: c12:PetCount2.java // Using class literals. import java.util.*;
public class PetCount2 { public static void main(String[] args) throws Exception { ArrayList pets = new ArrayList(); Class[] petTypes = { // Class literals: Pet.class, Dog.class, Pug.class, Cat.class, Rodent.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // Offset by one to eliminate Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.add( petTypes[rnd].newInstance()); } } catch(InstantiationException e) { System.err.println("Cannot instantiate"); throw e; } catch(IllegalAccessException e) { System.err.println("Cannot access"); throw e; } HashMap h = new HashMap(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.get(i); if(o instanceof Pet) ((Counter)h.get("class Pet")).i++; if(o instanceof Dog) ((Counter)h.get("class Dog")).i++; if(o instanceof Pug) ((Counter)h.get("class Pug")).i++; if(o instanceof Cat) ((Counter)h.get("class Cat")).i++; if(o instanceof Rodent) ((Counter)h.get("class Rodent")).i++; if(o instanceof Gerbil) ((Counter)h.get("class Gerbil")).i++; if(o instanceof Hamster) ((Counter)h.get("class Hamster")).i++; } for(int i = 0; i < pets.size(); i++) System.out.println(pets.get(i).getClass()); Iterator keys = h.keySet().iterator(); while(keys.hasNext()) { String nm = (String)keys.next(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantity: " + cnt.i); } } } ///:~
|
 |
//: c12:PetCount2.java // Utiliser les littéraux de classe. import java.util.*;
public class PetCount2 { public static void main(String[] args) throws Exception { ArrayList pets = new ArrayList(); Class[] petTypes = { // Littéraux de classe: Pet.class, Chien.class, Carlin.class, Chat.class, Rongeur.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // on ajoute 1 pour éliminer Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.add( petTypes[rnd].newInstance()); } } catch(InstantiationException e) { System.err.println("Instantiation impossible"); throw e; } catch(IllegalAccessException e) { System.err.println("Accès impossible"); throw e; } HashMap h = new HashMap(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.get(i); if(o instanceof Pet) ((Counter)h.get("class Pet")).i++; if(o instanceof Chien) ((Counter)h.get("class Chien")).i++; if(o instanceof Carlin) ((Counter)h.get("class Carlin")).i++; if(o instanceof Chat) ((Counter)h.get("class Chat")).i++; if(o instanceof Rongeur) ((Counter)h.get("class Rongeur")).i++; if(o instanceof Gerbil) ((Counter)h.get("class Gerbil")).i++; if(o instanceof Hamster) ((Counter)h.get("class Hamster")).i++; } for(int i = 0; i < pets.size(); i++) System.out.println(pets.get(i).getClass()); Iterator keys = h.keySet().iterator(); while(keys.hasNext()) { String nm = (String)keys.next(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantité: " + cnt.i); } } } ///:~
|
 |
 |
 |
Here, the typenames array has been
removed in favor of getting the type name strings from the Class object.
Notice that the system can distinguish between classes and
interfaces.
|
 |
Ici, le tableau typenames a été enlevé, on préfère obtenir
de l'objet Class les chaînes identifiant les types. Notons que ce système permet
au besoin de différencier classes et interfaces.
|
 |
 |
 |
You can also see that the creation of
petTypes does not need to be surrounded by a try block since
it’s evaluated at compile-time and thus won’t throw any exceptions,
unlike Class.forName( ).
|
 |
On peut aussi remarquer que la création de petTypes ne
nécessite pas l'utilisation d'un block try puisqu'il est évalué à la compilation
et ne lancera donc aucune exception, contrairement à Class.forName().
|
 |
 |
 |
When the Pet objects are
dynamically created, you can see that the random number is restricted so it is
between one and petTypes.length and does not include zero. That’s
because zero refers to Pet.class, and presumably a generic Pet
object is not interesting. However, since Pet.class is part of
petTypes the result is that all of the pets get counted.
|
 |
Quand les objets Pet sont créés dynamiquement, vous pouvez
voir que le nombre aléatoire généré est compris entre un (ndt inclus) et
petTypes.length (ndt exclus), donc ne peut pas prendre la valeur zéro. C'est parce
que zéro réfère à Pet.class, et que nous supposons que créer un objet générique
Pet n'est pas intéressant. Cependant, comme Pet.class fait partie
de petTypes, le nombre total d'animaux familiers est compté.
|
 |
 |
 |
A dynamic instanceof
|
 |
Un instanceof dynamique
|
 |
 |
 |
The Class
isInstance
method provides a way to dynamically call the instanceof operator. Thus,
all those tedious instanceof statements can be removed in the
PetCount example:
|
 |
La méthode isInstance de Class
fournit un moyen d'appeler dynamiquement l'opérateur instanceof. Ainsi, toutes ces
ennuyeuses expressions instanceof peuvent être supprimées de l'exemple
PetCount :
|
 |
 |
 |
//: c12:PetCount3.java // Using isInstance(). import java.util.*;
public class PetCount3 { public static void main(String[] args) throws Exception { ArrayList pets = new ArrayList(); Class[] petTypes = { Pet.class, Dog.class, Pug.class, Cat.class, Rodent.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // Offset by one to eliminate Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.add( petTypes[rnd].newInstance()); } } catch(InstantiationException e) { System.err.println("Cannot instantiate"); throw e; } catch(IllegalAccessException e) { System.err.println("Cannot access"); throw e; } HashMap h = new HashMap(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.get(i); // Using isInstance to eliminate individual // instanceof expressions: for (int j = 0; j < petTypes.length; ++j) if (petTypes[j].isInstance(o)) { String key = petTypes[j].toString(); ((Counter)h.get(key)).i++; } } for(int i = 0; i < pets.size(); i++) System.out.println(pets.get(i).getClass()); Iterator keys = h.keySet().iterator(); while(keys.hasNext()) { String nm = (String)keys.next(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantity: " + cnt.i); } } } ///:~
|
 |
//: c12:PetCount3.java // Utiliser isInstance(). import java.util.*;
public class PetCount3 { public static void main(String[] args) throws Exception { ArrayList pets = new ArrayList(); Class[] petTypes = { Pet.class, Chien.class, Carlin.class, Chat.class, Rongeur.class, Gerbil.class, Hamster.class, }; try { for(int i = 0; i < 15; i++) { // Ajoute 1 pour éliminer Pet.class: int rnd = 1 + (int)( Math.random() * (petTypes.length - 1)); pets.add( petTypes[rnd].newInstance()); } } catch(InstantiationException e) { System.err.println("Instantiation impossible"); throw e; } catch(IllegalAccessException e) { System.err.println("Accès impossible"); throw e; } HashMap h = new HashMap(); for(int i = 0; i < petTypes.length; i++) h.put(petTypes[i].toString(), new Counter()); for(int i = 0; i < pets.size(); i++) { Object o = pets.get(i); // Utiliser isInstance pour automatiser // l'utilisation des instanceof : // Ndt: Pourquoi ce ++j ???? for (int j = 0; j < petTypes.length; ++j) if (petTypes[j].isInstance(o)) { String key = petTypes[j].toString(); ((Counter)h.get(key)).i++; } } for(int i = 0; i < pets.size(); i++) System.out.println(pets.get(i).getClass()); Iterator keys = h.keySet().iterator(); while(keys.hasNext()) { String nm = (String)keys.next(); Counter cnt = (Counter)h.get(nm); System.out.println( nm.substring(nm.lastIndexOf('.') + 1) + " quantity: " + cnt.i); } } } ///:~
|
 |
 |
 |
You can see that the
isInstance( ) method has eliminated the need for the
instanceof expressions. In addition, this means that you can add new
types of pets simply by changing the petTypes array; the rest of the
program does not need modification (as it did when using the instanceof
expressions).
|
 |
On peut noter que l'utilisation de la méthode isInstance()
a permis d'éliminer les expressions instanceof. De plus, cela signifie que de nouveaux types
d'animaux familiers peuvent être ajoutés simplement en modifiant le tableau
petTypes ; le reste du programme reste inchangé (ce qui n'est pas le cas lorsqu'on
utilise des instanceof).
|
 |
 |
 |
instanceof vs. Class equivalence
|
 |
instanceof vs. équivalence de classe
|
 |
 |
 |
When querying for type information,
there’s an important difference between either form of instanceof
(that is, instanceof or isInstance( ), which produce
equivalent results) and the direct comparison of the Class objects.
Here’s an example that demonstrates the difference:
|
 |
Lorsque vous demandez une information de type, il y a une différence
importante entre l'utilisation d'une forme de instanceof
(instanceof ou isInstance(), qui produisent des résultats
équivalents) et la comparaison directe des objets Class. Voici un exemple qui
illustre cette différence :
|
 |
 |
 |
//: c12:FamilyVsExactType.java // The difference between instanceof and class
class Base {} class Derived extends Base {}
public class FamilyVsExactType { static void test(Object x) { System.out.println("Testing x of type " + x.getClass()); System.out.println("x instanceof Base " + (x instanceof Base)); System.out.println("x instanceof Derived " + (x instanceof Derived)); System.out.println("Base.isInstance(x) " + Base.class.isInstance(x)); System.out.println("Derived.isInstance(x) " + Derived.class.isInstance(x)); System.out.println( "x.getClass() == Base.class " + (x.getClass() == Base.class)); System.out.println( "x.getClass() == Derived.class " + (x.getClass() == Derived.class)); System.out.println( "x.getClass().equals(Base.class)) " + (x.getClass().equals(Base.class))); System.out.println( "x.getClass().equals(Derived.class)) " + (x.getClass().equals(Derived.class))); } public static void main(String[] args) { test(new Base()); test(new Derived()); } } ///:~
|
 |
//: c12:FamilyVsExactType.java // La différence entre instanceof et class
class Base {} class Derived extends Base {}
public class FamilyVsExactType { static void test(Object x) { System.out.println("Teste x de type " + x.getClass()); System.out.println("x instanceof Base " + (x instanceof Base)); System.out.println("x instanceof Derived " + (x instanceof Derived)); System.out.println("Base.isInstance(x) " + Base.class.isInstance(x)); System.out.println("Derived.isInstance(x) " + Derived.class.isInstance(x)); System.out.println( "x.getClass() == Base.class " + (x.getClass() == Base.class)); System.out.println( "x.getClass() == Derived.class " + (x.getClass() == Derived.class)); System.out.println( "x.getClass().equals(Base.class)) " + (x.getClass().equals(Base.class))); System.out.println( "x.getClass().equals(Derived.class)) " + (x.getClass().equals(Derived.class))); } public static void main(String[] args) { test(new Base()); test(new Derived()); } } ///:~
|
 |
 |
 |
The test( ) method performs
type checking with its argument using both forms of instanceof. It then
gets the Class reference and uses == and equals( ) to
test for equality of the Class objects. Here is the
output:
|
 |
La méthode test() effectue une vérification du type de son
argument en utilisant les deux formes de instanceof. Elle récupère ensuite la
référence sur l'objet Class et utilise == et
equals() pour tester l'égalité entre les objets Class. Le
résultat est le suivant :
|
 |
 |
 |
Testing x of type class Base x instanceof Base true x instanceof Derived false Base.isInstance(x) true Derived.isInstance(x) false x.getClass() == Base.class true x.getClass() == Derived.class false x.getClass().equals(Base.class)) true x.getClass().equals(Derived.class)) false Testing x of type class Derived x instanceof Base true x instanceof Derived true Base.isInstance(x) true Derived.isInstance(x) true x.getClass() == Base.class false x.getClass() == Derived.class true x.getClass().equals(Base.class)) false x.getClass().equals(Derived.class)) true
|
 |
Teste x de type class Base x instanceof Base true x instanceof Derived false Base.isInstance(x) true Derived.isInstance(x) false x.getClass() == Base.class true x.getClass() == Derived.class false x.getClass().equals(Base.class)) true x.getClass().equals(Derived.class)) false Teste x de type class Derived x instanceof Base true x instanceof Derived true Base.isInstance(x) true Derived.isInstance(x) true x.getClass() == Base.class false x.getClass() == Derived.class true x.getClass().equals(Base.class)) false x.getClass().equals(Derived.class)) true
|
 |
 |
 |
Reassuringly, instanceof and
isInstance( ) produce exactly the same results, as do
equals( ) and ==. But the tests themselves draw different
conclusions. In keeping with the concept of type, instanceof says
“are you this class, or a class derived from this class?” On the
other hand, if you compare the actual Class objects using ==,
there is no concern with inheritance—it’s either the exact type or
it
isn’t.
|
 |
Il est rassurant de constater que instanceof et
isIntance() produisent des résultats identiques, de même que
equals() et ==. Mais les tests eux-mêmes aboutissent à des
conclusions différentes. instanceof teste le concept de type et signifie « es-tu
de cette classe, ou d'une classe dérivée ? ». Autrement, si on compare les objets
Class en utilisant ==, il n'est plus question d'héritage -
l'objet est de ce type ou non.
|
 |
 |
 |
RTTI syntax
|
 |
La syntaxe du RTTI
|
 |
 |
 |
Java performs its
RTTI using the Class
object, even if you’re doing something like a cast. The class Class
also has a number of other ways you can use RTTI.
|
 |
Java effectue son identification dynamique de type (RTTI) à l'aide de
l'objet Class, même lors d'un transtypage. La classe Class
dispose aussi de nombreuses autres manières d'être utilisée pour le RTTI.
|
 |
 |
 |
First, you must get a reference to the
appropriate Class object. One way to do this, as shown in the previous
example, is to use a string and the Class.forName( ) method. This is
convenient because you don’t need an object of that type in order to get
the Class reference. However, if you do already have an object of the
type you’re interested in, you can fetch the Class reference by
calling a method that’s part of the Object root class:
getClass( ). This
returns the Class reference representing the actual type of the object.
Class has many interesting methods, demonstrated in the following
example:
|
 |
Premièrement, il faut obtenir une référence sur l'objet
Class approprié. Une manière de le faire, comme nous l'avons vu dans l'exemple
précédent, est d'utiliser une chaîne de caractères et la méthode Class.forName().
C'est très pratique car il n'est pas nécessaire d'avoir un objet de ce type pour obtenir la
référence sur l'objet Class. Néanmoins, si vous avez déjà un objet de ce type,
vous pouvez retrouver la référence à l'objet Class en appelant une méthode qui
appartient à la classe racine Object : getClass(). Elle
retourne une référence sur l'objet Class représentant le type actuel de l'objet.
Class a de nombreuses méthodes intéressantes, comme le montre l'exemple suivant
:
|
 |
 |
 |
//: c12:ToyTest.java // Testing class Class.
interface HasBatteries {} interface Waterproof {} interface ShootsThings {} class Toy { // Comment out the following default // constructor to see // NoSuchMethodError from (*1*) Toy() {} Toy(int i) {} }
class FancyToy extends Toy implements HasBatteries, Waterproof, ShootsThings { FancyToy() { super(1); } }
public class ToyTest { public static void main(String[] args) throws Exception { Class c = null; try { c = Class.forName("FancyToy"); } catch(ClassNotFoundException e) { System.err.println("Can't find FancyToy"); throw e; } printInfo(c); Class[] faces = c.getInterfaces(); for(int i = 0; i < faces.length; i++) printInfo(faces[i]); Class cy = c.getSuperclass(); Object o = null; try { // Requires default constructor: o = cy.newInstance(); // (*1*) } catch(InstantiationException e) { System.err.println("Cannot instantiate"); throw e; } catch(IllegalAccessException e) { System.err.println("Cannot access"); throw e; } printInfo(o.getClass()); } static void printInfo(Class cc) { System.out.println( "Class name: " + cc.getName() + " is interface? [" + cc.isInterface() + "]"); } } ///:~
|
 |
//: c12:ToyTest.java // Teste la classe Class.
interface HasBatteries {} interface Waterproof {} interface ShootsThings {} class Toy { // Commenter le constructeur par // défault suivant pour obtenir // NoSuchMethodError depuis (*1*) Toy() {} Toy(int i) {} }
class FancyToy extends Toy implements HasBatteries, Waterproof, ShootsThings { FancyToy() { super(1); } }
public class ToyTest { public static void main(String[] args) throws Exception { Class c = null; try { c = Class.forName("FancyToy"); } catch(ClassNotFoundException e) { System.err.println("Ne trouve pas FancyToy"); throw e; } printInfo(c); Class[] faces = c.getInterfaces(); for(int i = 0; i < faces.length; i++) printInfo(faces[i]); Class cy = c.getSuperclass(); Object o = null; try { // Nécessite un constructeur par défaut : o = cy.newInstance(); // (*1*) } catch(InstantiationException e) { System.err.println("Instanciation impossible"); throw e; } catch(IllegalAccessException e) { System.err.println("Accès impossible"); throw e; } printInfo(o.getClass()); } static void printInfo(Class cc) { System.out.println( "Class nom: " + cc.getName() + " est une interface ? [" + cc.isInterface() + "]"); } } ///:~
|
 |
 |
 |
You can see that class FancyToy is
quite complicated, since it inherits from Toy and implements the
interfaces of HasBatteries, Waterproof, and
ShootsThings. In main( ), a Class reference is created
and initialized to the FancyToy Class using forName( )
inside an appropriate try block.
|
 |
On peut voir que la classe FancyToy est assez compliquée,
puisqu'elle hérite de Toy et implémente les interfaces
HasBatteries, Waterproof et ShootThings. Dans
main(), une référence de Class est créée et initialisée pour la
classe FancyToy en utilisant forName() à l'intérieur du block
try approprié.
|
 |
 |
 |
The Class.getInterfaces( )
method returns an array of
Class objects representing the interfaces that are contained in the
Class object of interest.
|
 |
La méthode Class.getInterfaces() retourne un tableau
d'objets Class représentant les interfaces qui sont contenues dans l'objet en
question.
|
 |
 |
 |
If you have a Class object you can
also ask it for its direct base class using
getSuperclass( ).
This, of course, returns a Class reference that you can further query.
This means that, at run-time, you can discover an object’s entire class
hierarchy.
|
 |
Si vous avez un objet Class, vous pouvez aussi lui
demander la classe dont il hérite directement en utilisant la méthode getSuperclass(). Celle-ci retourne, bien sûr, une référence de
Class que vous pouvez interroger plus en détail. Cela signifie qu'à l'éxécution,
vous pouvez découvrir la hiérarchie de classe complète d'un objet.
|
 |
 |
 |
The
newInstance( )
method of Class can, at first, seem like just another way to
clone( ) an object. However, you can create a new object with
newInstance( ) without an existing object, as seen here,
because there is no Toy object—only cy, which is a reference
to y’s Class object. This is a way to implement a
“virtual constructor,” which allows you to say “I don’t
know exactly what type you are, but create yourself properly anyway.” In
the example above, cy is just a Class reference with no further
type information known at compile-time. And when you create a new instance, you
get back an Object reference. But that reference is pointing to a
Toy object. Of course, before you can send any messages other than those
accepted by Object, you have to investigate it a bit and do some casting.
In addition, the class that’s being created with
newInstance( ) must have a default constructor. In the next section,
you’ll see how to dynamically create objects of classes using any
constructor, with the Java reflection API.
|
 |
La méthode newInstance() de Class
peut, au premier abord, ressembler à un autre moyen de cloner()
un objet. Néanmoins, vous pouvez créer un nouvel objet avec newInstance() sans un
objet existant, comme nous le voyons ici, car il n'y a pas d'objets Toy -
seulement cy qui est une référence sur l'objet Class de
y. C'est un moyen de construire un « constructeur virtuel », qui vous permet
d'exprimer « je ne sais pas exactement de quel type vous êtes, mais créez-vous proprement ». Dans
l'exemple ci-dessus, cy est seulement une référence sur Class
sans aucune autre information à la compilation. Et lorsque vous créez une nouvelle instance, vous
obtenez une référence sur un Object. Mais cette référence pointe sur un objet
Toy. Bien entendu, avant de pouvoir envoyer d'autres messages que ceux acceptés
par Object, vous devez l'examiner un peu plus et effectuer quelques transtypages.
De plus, la classe de l'objet créé par newInstance() doit avoir un constructeur
par défaut. Dans la prochaine section, nous verrons comment créer dynamiquement des objets de
classes utilisant n'importe quel constructeur, avec l'API de réflexion Java.
|
 |
 |
 |
The final method in the listing is
printInfo( ), which
takes a Class reference and gets its name with
getName( ), and
finds out whether it’s an interface with
isInterface( ).
|
 |
La dernière méthode dans le listing est printInfo(),
qui prend en paramètre une référence sur Class, récupère son nom
avec getName(), et détermine si c'est une interface
avec isInterface().
|
 |
 |
 |
The output from this program
is:
|
 |
Le résultat de ce programme est :
|
 |
 |
 |
Class name: FancyToy is interface? [false] Class name: HasBatteries is interface? [true] Class name: Waterproof is interface? [true] Class name: ShootsThings is interface? [true] Class name: Toy is interface? [false]
|
 |
Class nom: FancyToy est une interface ? [false] Class nom: HasBatteries est une interface ? [true] Class nom: Waterproof est une interface ? [true] Class nom: ShootsThings est une interface ? [true] Class nom: Toy est une interface ? [false]
|
 |
 |
 |
Thus, with the Class object you
can find out just about everything you want to know about an
object.
|
 |
Ainsi, avec l'objet Class, vous pouvez découvrir vraiment
tout ce que vous voulez savoir sur un objet.
|
 |
 |
 |
Reflection: run-time class
information
|
 |
Réflexion : information de classe dynamique
|
 |
 |
 |
If you don’t know the precise type
of an object, RTTI will tell you. However, there’s a limitation: the type
must be known at compile-time in order for you to be able to detect it using
RTTI and do something useful with the information. Put another way, the compiler
must know about all the classes you’re working with for
RTTI.
|
 |
Si vous ne connaissez pas le type précis d'un objet, le RTTI vous le dira.
Néanmoins, il y a une limitation : le type doit être connu à la compilation afin que vous puissiez
le détecter en utilisant le RTTI et faire quelque chose d'intéressant avec cette information.
Autrement dit, le compilateur doit connaître toutes les classes que vous utilisez pour le
RTTI.
|
 |
 |
 |
This doesn’t seem like that much of
a limitation at first, but suppose you’re given a reference to an object
that’s not in your program space. In fact, the class of the object
isn’t even available to your program at compile-time. For example, suppose
you get a bunch of bytes from a disk file or from a network connection and
you’re told that those bytes represent a class. Since the compiler
can’t know about the class while it’s compiling the code, how can
you possibly use such a class?
|
 |
Ceci peut ne pas paraître une grande limitation à première vue, mais
supposons que l'on vous donne une référence sur un objet qui n'est pas dans l'espace de votre
programme. En fait, la classe de l'objet n'est même pas disponible lors de la compilation. Par
exemple, supposons que vous récupériez un paquet d'octets à partir d'un fichier sur disque ou via
une connexion réseau et que l'on vous dise que ces octets représentent une classe. Puisque le
compilateur ne peut pas connaître la classe lorsqu'il compile le code, comment pouvez vous utilisez
cette classe ?
|
 |
 |
 |
In a traditional programming environment
this seems like a far-fetched scenario. But as we move into a larger programming
world there are important cases in which this happens. The first is
component-based programming, in which you build projects using
Rapid Application Development (RAD) in an
application builder tool. This is a visual approach to creating a program (which
you see on the screen as a “form”) by moving icons that represent
components onto the form. These components are then configured by setting some
of their values at program time. This design-time configuration requires that
any component be instantiable, that it exposes parts of itself, and that it
allows its values to be read and set. In addition, components that handle GUI
events must expose information about appropriate methods so that the RAD
environment can assist the programmer in overriding these event-handling
methods. Reflection provides the mechanism to detect the available methods and
produce the method names. Java provides a structure for
component-based programming through JavaBeans (described in Chapter
13).
|
 |
Dans un environnement de travail traditionnel cela peut sembler un scénario
improbable. Mais dès que l'on se déplace dans un monde de la programmation plus vaste, il y a des
cas importants dans lesquels cela arrive. Le premier est la programmation par composants, dans
lequel vous construisez vos projets en utilisant le Rapid Application Development
(RAD) dans un constructeur d'application. C'est une approche visuelle pour créer un programme (que
vous voyez à l'écran comme un « formulaire » (form)) en déplaçant des icônes qui
représentent des composants dans le formulaire. Ces composants sont alors configurés en fixant
certaines de leurs valeurs. Cette configuration durant la conception nécessite que chacun des
composants soit instanciable, qu'il dévoile une partie de lui-même et qu'il permette que ses
valeurs soient lues et fixées. De plus, les composants qui gèrent des événements dans une GUI
doivent dévoiler des informations à propos des méthodes appropriées pour que l'environnement RAD
puisse aider le programmeur à redéfinir ces méthodes de gestion d'événements. La réflexion fournit
le mécanisme pour détecter les méthodes disponibles et produire leurs noms. Java fournit une
structure de programmation par composants au travers de JavaBeans (décrit dans le chapitre
13).
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |