next up previous contents index
Next: 20 Threads Up: Java: Le langage Previous: 18 Programmation système

Subsections

19 Programmation dynamique

Avec la classe java.lang.Class, il est possible de déterminer la classe à laquelle appartient un objet, obtenir des informations sur les méthodes, les champs, les constructeurs, les super classes etc. Il permet également de créer des objets alors que l'on ne connaît la classe à laquelle ils appartiennent qu'à l'exécution.

19.1 Ausculter une classe

19.1.1 La classe java.lang.Class

  Les instances de la classe Class représente les classes et interfaces existants dans une application Java . Chaque classe, interface, tableau d'un type particulier sont représentés par une instance de la classe Class. Il en est de même des types primitifs et du type void. Cette classe ne fournit pas de constructeur, les instances de cette classe sont créées par la machine Java .

 

   public final class Class implements java.io.Serializable {
      private Class()
      public String toString()
      public static native Class forName(String className) throws ClassNotFoundException;
      public native Object newInstance() throws InstantiationException, IllegalAccessException;
      public native boolean isInstance(Object obj)
      public native boolean isAssignableFrom(Class cls)
      public native boolean isInterface()
      public native boolean isArray()
      public native boolean isPrimitive()
      public native String getName()
      public native ClassLoader getClassLoader()
      public native Class getSuperclass()
      public native Class[] getInterfaces()
      public native Class getComponentType()
      public native int getModifiers()
      public native Object[] getSigners()
      native void setSigners(Object[] signers)
      public Class getDeclaringClass()
      public Class[] getClasses()
      public Field[] getFields() throws SecurityException
      public Method[] getMethods() throws SecurityException
      public Constructor[] getConstructors() throws SecurityException
      public Field getField(String name) throws NoSuchFieldException, SecurityException
      public Method getMethod(String name, Class[] parameterTypes) throws NoSuchMethodException, SecurityException
      public Constructor getConstructor(Class[] parameterTypes) throws NoSuchMethodException, SecurityException
      public Class[] getDeclaredClasses() throws SecurityException
      public Field[] getDeclaredFields() throws SecurityException
      public Method[] getDeclaredMethods() throws SecurityException
      public Constructor[] getDeclaredConstructors() throws SecurityException
      public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException
      public Method getDeclaredMethod(String name, Class[] parameterTypes) throws NoSuchMethodException, SecurityException
      public Constructor getDeclaredConstructor(Class[] parameterTypes) throws NoSuchMethodException, SecurityException
      public InputStream getResourceAsStream(String name)
      public java.net.URL getResource(String name)
   }

On ne peut qu'obtenir des instances de cette classe qu'à travers les différentes méthodes de cette classe, de la classe Object, de la classe ClassLoader, etc.

Lorsqu'un nom de la classe C est connu à la compilation, il est possible de créer l'instance de la classe Class qui représente C en suffixant le nom complet de la classe par ".class " ou en utilisant la méthode forName de la classe Class

 
Class c = java.util.Date.class;
Class c = Class.forName("java.util.Date");

Si le nom de la classe C n'est connu qu'à l'exécution, la méthode getCalss appliqué à un objet permet d'obtenir une instance de la classe Class.

 
Class c = obj.getClass();

Ainsi, avec une chaine de caractères, on peut parler de toutes les classes. Comment faire pour parler des tableaux, matrices, etc. Pour ce faire, Java définit représentation textuelle permet de parler d'un type de donnée sans devoir créer une instance de cet objet.

 Un tableau d'éléments de type T est représenté par la chaîne "[T". Les types primitifs sont représentés par une chaîne de caractères d'un caractère (B pour byte, C pour char, D pour double, F pour float,Member I pour int, J pour long, S pour short, Z pour boolean). Une classe ou interface est représentée par la chaîne "LNomDeClasse; ".

Par exemple, un objet de la classe Date est représenté par la chaîne "java.util.Date" et une matrice d'objets de classe Date se représente par la chaîne "[[Ljava.util.Date;".

 public String getName ()

Retourne la représentation textuelle d'une classe.
 
 (new Object[3]).getClass().getName()
 (new Date())..getClass().getName()
retournent les chaînes
 
"[Ljava.lang.Object;"
"java.util.Date"
 public static native Class forName (String className) throws ClassNotFoundException
Retourne un objet de type Class qui code la classe désigné par la chaîne className.
 
Class t = Class.forName("java.lang.Thread");

 public Object newInstance () throws InstantiationException, IllegalAccessException

Créé une instance d'une classe
 
Class c = Class.forName("java.util.Date");
c.newInstance();   // Création d'une instance de java.util.Date

 public native int getModifiers () throws InstantiationException, IllegalAccessException

Retourne les modifiers de la classe ou de l'interface sou la forme d'un entier. Un modifier est un de ces mots clés qui précède la la définition d'une classe, d'une méthode ou d'un champ: public , protected, private, final, etc. Ces modifiers sont représentés par des entiers dont les valeurs sont définies dans la classe Modifier qui correspondent à un champ de bits.
 
Class c = Class.forName("java.util.Date");
int m = c.getModifiers();
if (Modifier.isPublic(m)) System.out.print("Public ");
...
if (Modifier.isabstract(m)) System.out.print("Abstract ");
...

 public native Class getSuperclass ()

Retourne l'instance de la classe Class qui représente la super classe. Si l'instance sur laquelle cette méthode s'applique est un objet de classe Object, la valeur null est renvoyée.
 
Class c = Class.forName("java.util.Stack");
Class supclass = c.getSuperclass();
String supername = (supclass == null) ? "Aucun" : supclass.getName();

 public class[] getInterfaces ()

Retourne un tableau d'instance de la classe Class qui représente toutes les interfaces qu'implante l'objet sur lequel cette méthode s'applique.
 
Class c = Class.forName("java.util.Stack");
Class ifs[] = s.getInterfaces();
for (int i = 0; i < ifs.length; i++)
   System.out.println("Interface[" + i + "] = " + ifs[i]);

 public Field[] getFields () throws SecurityException

Retourne un tableau d'instance de la classe Field qui représente tous les champs publiques de l'objet sur lequel cette méthode s'applique.
 public Field[] getDeclaredFields () throws SecurityException
Retourne que les champs (public, protected, private) définis dans cette classe uniquement; pas les champs hérités des super classes.
 
Class c = Class.forName("java.util.Stack");
Field [] ch = c.getDeclaredFields();
for (int i = 0; i < ch.length; i++)
   System.out.println("Champs[" + i + "] = " + ch[i]);
 public Field[] getMethods () throws SecurityException
Retourne un tableau d'instance de la classe Method qui représente toutes les méthodes publiques de l'objet sur lequel cette méthode s'applique.
 public Field[] getDeclaredMethods () throws SecurityException
Retourne toutes les méthodes (public, protected, private) définies dans cette classe uniquement; pas les méthodes héritées des super classes.
 
Class c = Class.forName("java.util.Stack");
Field [] mt = c.getDeclaredMethods();
for (int i = 0; i < mt.length; i++)
   System.out.println("Méthodes[" + i + "] = " + mt[i]);

 public Constructor[] getConstructors () throws SecurityException

Retourne un tableau d'instance de la classe Constructor qui représente tous les constructeurs publiques de la classe de l'objet sur lequel cette méthode s'applique.
 public Field[] getDeclaredConstructors () throws SecurityException
Retourne tous les constructeurs définis dans cette classe (public; private, protected).
 
Class c = Class.forName("java.util.Stack");
Field [] mt = c.getDeclaredMethods();
for (int i = 0; i < mt.length; i++)
   System.out.println("Méthodes[" + i + "] = " + mt[i]);

 

A TERMINER

 

   import java.lang.Class;
   import java.lang.Boolean;
   import java.io.*;
   import java.lang.reflect.*;

   class InfoClass {
      public static void main (String args[]) throws Exception {
         Class s = Class.forName(args[0]);   
         Class supclass = s.getSuperclass();
         String supername = (supclass == null) ? "Aucun" : supclass.getName();
         Class ifs[] = s.getInterfaces();
         ClassLoader loader = s.getClassLoader();
         
         Field [] ch = s.getDeclaredFields();
         Method [] m = s.getDeclaredMethods();
         imprimerModifier(s.getModifiers());
         System.out.println("Nom de la classe : " + s);
         System.out.println("Nom de la super classe : " + supername);
         System.out.println("Class Loader : " + loader);
      
         for (int i = 0; i < ifs.length; i++)
            System.out.println("Interface[" + i + "] = " + ifs[i]);
         for (int i = 0; i < ch.length; i++)
            System.out.println("Champs[" + i + "] = " + ch[i]);
         for (int i = 0; i < m.length; i++)
            System.out.println("Méthodes[" + i + "] = " + m[i]);
      
         if (s.isInterface()) 
            System.out.println(s+ " est une Interface");
         else 
            System.out.println(s+ " n'est pas une Interface");
      } 
      static void imprimerModifier(int c) {
         System.out.print("Modifier(s) : ");
         if ((c & Modifier.PUBLIC) != 0) System.out.print("PUBLIC "); 
         if ((c & Modifier.PRIVATE) != 0) System.out.print("PRIVATE "); 
         if ((c & Modifier.PROTECTED) != 0) System.out.print("PROTECTED "); 
         if ((c & Modifier.STATIC) != 0) System.out.print("STATIC "); 
         if ((c & Modifier.FINAL) != 0) System.out.print("FINAL "); 
         if ((c & Modifier.SYNCHRONIZED) != 0) System.out.print("SYNCHRONIZED "); 
         if ((c & Modifier.VOLATILE) != 0) System.out.print("VOLATILE "); 
         if ((c & Modifier.TRANSIENT) != 0) System.out.print("TRANSIENT "); 
         if ((c & Modifier.NATIVE) != 0) System.out.print("NATIVE ");
         if ((c & Modifier.INTERFACE) != 0) System.out.print("INTERFACE ");
         if ((c & Modifier.ABSTRACT) != 0) System.out.print("ABSTRACT "); 
         System.out.println();
      }
   }

Voici les affichages produit par l'exécution suivante:

 
% java InfoClass java.util.Stack 
Modifier(s) : PUBLIC
Nom de la classe : class java.util.Stack
Nom de la super classe : java.util.Vector
Class Loader : null
Champs[0] = private static final long java.util.Stack.serialVersionUID
Champs[0] = public java.lang.Object java.util.Stack.push(java.lang.Object)
Champs[1] = public synchronized java.lang.Object java.util.Stack.pop()
Champs[2] = public synchronized java.lang.Object java.util.Stack.peek()
Champs[3] = public boolean java.util.Stack.empty()
Champs[4] = public synchronized int java.util.Stack.search(java.lang.Object)
class java.util.Stack n'est pas une Interface

Dans cet exemple, nous nous sommes contenté d'afficher ce que les méthodes ont retournées comme valeurs. Nous n'avons pas du tout parler des différents types de données qui interviennent dans ce programme. Par exemple, la méthode getMethods retourne un tableau d'objet de la classe Method. Le package java.lang.reflect définit un ensemble de classes pour manipuler ce type d'objets.

La version de jdk1.1 fournit pour ce package :


Les Classes:  
Array:  
Constructor:  
Field:  
Method:  
Modifier:  


Les interfaces:  
Membre:  


19.1.2 L'interface java.lang.reflect.Member

 
 

   public interface Member {
      public static final int PUBLIC
      public static final int DECLARED
      public abstract Class getDeclaringClass()
      public abstract String getName()
      public abstract int getModifiers()
   }

19.1.3 La classe java.lang.reflect.Modifier

 

 

   public final class Modifier {
      public static final int PUBLIC
      public static final int PRIVATE
      public static final int PROTECTED
      public static final int STATIC
      public static final int FINAL
      public static final int SYNCHRONIZED
      public static final int VOLATILE
      public static final int TRANSIENT
      public static final int NATIVE
      public static final int INTERFACE
      public static final int ABSTRACT
      public Modifier()
      public static boolean isPublic(int mod)
      public static boolean isPrivate(int mod)
      public static boolean isProtected(int mod)
      public static boolean isStatic(int mod)
      public static boolean isFinal(int mod)
      public static boolean isSynchronized(int mod)
      public static boolean isVolatile(int mod)
      public static boolean isTransient(int mod)
      public static boolean isNative(int mod)
      public static boolean isInterface(int mod)
      public static boolean isAbstract(int mod)
      public static String toString(int mod)
   }

19.2 Manipuler dynamiquement des objets

19.3 Création d'objets

 

Lorsque le type de l'objet à créer n'est connu qu'à l'exécution, il n'est pas possible d'utiliser les constructeurs de manière standard:

 
Vector v = new Vector();
Il faut alors passer par la méthode newInstance:
 
try {
   Class c = Class.forName("java.util.vector");
   v = c.newInstance();
}
catch (InstantiationException e) { System.out.println(e); }
catch (IllegalAccessException e) { System.out.println(e); }
catch (ClassNotFoundException e) { System.out.println(e); }
Il reste toutefois un point à éclaircir: comment créer dynamiquement un objet en utilisant un constructeur avec arguments:
 
Vector v = new Vector(100);

Remarquons l'argument que l'on passe dans ce constructeur est de type primitif (c'est un int). Or la méthode newInstance n'admet qu'un tableau d'objets; il faut donc convertir notre int en un objet de type Integer.

 
try {
   Class c = Class.forName("java.util.Vector");
   Class [] argsClass = int.class;
   Object[] args =  new Integer(100) ;
   constr = c.getConstructor(argsClass);
   v = constr.newInstance(args);
}
catch (InstantiationException e) { System.out.println(e); }
catch (IllegalAccessException e) { System.out.println(e); }
catch (ClassNotFoundException e) { System.out.println(e); }
catch (InvocationTargetException e) { System.out.println(e); }

 

   public final class Constructor implements Member {
      public Class getDeclaringClass()
      public String getName()
      public native int getModifiers()
      public Class[] getParameterTypes()
      public Class[] getExceptionTypes()
      public boolean equals(Object obj)
      public int hashCode()
      public String toString()
      public native Object newInstance(Object initargs[]) throws InstantiationException,
                                                                 IllegalAccessException,
                                                                 IllegalArgumentException,
                                                                 InvocationTargetException
   }

A partir d'une instance de Constructor, les méthodes getDeclaringClass, getName, getModifier getParameterTypes et getExceptionTypes permettent de récupérer la classe à laquelle ce constructeur appartient, le nom du du constructeur, les qualifiers du constructeur et les types des arguments et les exceptions que ce constructeur peut engendrer.

19.3.1 Les champs

  Il est, dans certaisn cas, intéressant de récupérer les insformations sur les champs d'une classe; à cette fin , la classe Field propose un ensemble de méthodes dans la classe Field.

 

   public final class Field implements Member {
      public Class getDeclaringClass()
      public String getName()
      public Class getType()
      public boolean equals(Object obj)
      public int hashCode()
      public String toString()
      public native Object get(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native boolean getBoolean(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native byte getByte(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native char getChar(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native short getShort(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native int getInt(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native long getLong(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native float getFloat(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native double getDouble(Object obj)
                                throws IllegalArgumentException, IllegalAccessException
      public native void set(Object obj, Object value)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setBoolean(Object obj, boolean z)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setByte(Object obj, byte b)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setChar(Object obj, char c)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setShort(Object obj, short s)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setInt(Object obj, int i)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setLong(Object obj, long l)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setFloat(Object obj, float f)
                                throws IllegalArgumentException, IllegalAccessException
      public native void setDouble(Object obj, double d)
                                throws IllegalArgumentException, IllegalAccessException
   }

Le méthode get générique ne revoie que des instances de classes, jamais des types primitifs. Avec cette méthodes, les types primitifs sont transformés en leur équivalent class wrapper . Les autres méthodes get sont là pour récupérer des type primitifs.

 
class X {
   int i;
   Integer I;
   int [] t = ...
}

class Y { ... public printFields(Object o) { ... try { Integer I; int i; Array t; Class c = o.getClass(); Field fi = c.getField("i"); I = c.getField("i").get(o); i = c.getField("i").getInt(o); I = c.getField("I").get(o); i = c.getField("I").getInt(o); // Erreur !!! t = c.getField("t").get(o); } catch (...) ... ... } }

Les méthodes set et settype permettent affecter des champs.

A partir d'une instance de Field, les méthodes getDeclaringClass, getName, getModifier et getType permettent de récupérer la classe à laquelle ce champ appartient, le nom du champ, les qualifiers du champ et le type (sous la forme d'un objet de type Class) du champ.

 
try {
   Class c = Class.forName("...");
   Object o = c.newInstance();
   Field f = c.getField("...");
   Interger nouveau = new Integer(200);
   f.set(o, nouveau);
\
catch(...) { ...}
...
}

19.3.2 Les méthodes

 Le sméthodes peuvent également se manipuler dynamiquement. Outre la manipulation des attributs d'une méthode, il est possible d'invoquer dynamiquement une méthode.

 

   public final class Method implements Member {
      public Class getDeclaringClass()
      public String getName()
      public native int getModifiers()
      public Class getReturnType()
      public Class[] getParameterTypes()
      public Class[] getExceptionTypes()
      public boolean equals(Object obj)
      public int hashCode()
      public String toString()
      public native Object invoke(Object obj, Object args[])
                                throws  IllegalAccessException,
                                        IllegalArgumentException,
                                        InvocationTargetException
   }

Voici un exmple d'invocation dynamique d'une méthode avec la méthode invoque de la classe Method.

 
try \{
   Class c = Class.forName("...");
   Object o = c.newInstance();
   Class[] argsClass =  {...};
   Method m = c.getMethod("Nom", argsClass);
   res = (type) m.invoke(...);
\}
catch (NoSuchMethodException e) \{ System.out.println(e); \}
catch (IllegalAccessException e) \{ System.out.println(e); \}
catch (InvocationTargetException e) \{ System.out.println(e); \}

A partir d'une instance de Method, les méthodes getDeclaringClass, getName, getModifier getParameterTypes getReturnType et getExceptionTypes permettent de récupérer la classe à laquelle cette méthode appartient, son nom, ses qualifiers et le type des arguments et de la valeur retournée ainsi que les exceptions que cette méthode peut engendrer.

19.4 Les tableaux

Comme nous l'avons déjà présenté plus haut, les tableaux d'objets ont une représentation textuelle de la forme "[[Ljava.util.Date;" pour désigner les matrices d'objets de type java.util.Date.

 

   public final class Array {
      public static Object newInstance(Class componentType, int length)
                                throws NegativeArraySizeException
      public static Object newInstance(Class componentType, int dimensions[])
                                throws IllegalArgumentException, NegativeArraySizeException
      public static native int getLength(Object array) throws IllegalArgumentException
      public static native Object get(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native boolean getBoolean(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native byte getByte(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native char getChar(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native short getShort(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native int getInt(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native long getLong(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native float getFloat(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native double getDouble(Object array, int index)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void set(Object array, int index, Object value)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setBoolean(Object array, int index, boolean z)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setByte(Object array, int index, byte b)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setChar(Object array, int index, char c)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setShort(Object array, int index, short s)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setInt(Object array, int index, int i)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setLong(Object array, int index, long l)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setFloat(Object array, int index, float f)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
      public static native void setDouble(Object array, int index, double d)
                                throws IllegalArgumentException, ArrayIndexOutOfBoundsException
   }

La classe Array permet un certain nombre de manipulation sur les tableaux. Les méthodes get (resp. getType ) et set (resp. setType ) de récupérer et d'affecter un élément du tableau.

La création dynamique d'un tableau peut se faire avec la méthode newInstance de cette classe, la méthode getLength donne la taille du tableau.

 

A TERMINER

19.5 Jdk 1.2

La version de jdk1.2 fournit pour ce package :


Les Classes:  
AccessibleObject:  
Array:  
Constructor:  
Field:  
Method:  
Modifier:  
ReflectPermission:  


Les interfaces:  
Membre:  


 

A TERMINER


next up previous contents index
Next: 20 Threads Up: Java: Le langage Previous: 18 Programmation système
Touraivane
6/12/1998