précédent | suivant | table des matières

Classe Class et réflexion

Sommaire
  1. La classe Class
  2. Obtenir une référence
  3. La méthode getName
  4. Obtenir des informations
  5. Aller plus loin ...
    1. Création d'instance
    2. Invocation de méthode
    3. Modification d'un attribut privé
    4. Programmation de javap

1 La classe Class

La réflexion est la capacité d'un programme à manipuler, en tant que données, les entités qui représentent l'état du programme pendant sa propre exécution. On distingue : 

La classe Class est une «méta-classe».

Les instances de la classe Class représentent les classes et les interfaces des objets utilisés dans une application ( y compris les tableaux ).

La création d'une instance de la classe Class se fait à la première création d'une instance de la classe, ou à l'appel de la méthode de classe de Class, forName(String nom) qui retourne une référence à l'instance de classe, en chargeant la classe si elle n'est pas déjà chargée.

Toute instance de classe peut accéder à l'instance de sa classe par la méthode getClass().

Supposons définies les classes suivantes : 

class A {
   static{ System.out.println(" chargement de A ");}
}

class B extends A{
   static{ System.out.println(" chargement de B ");}
}

class C {
   static{ System.out.println("chargement de C ");}
}

Alors les instructions suivantes : 

A a = new A();
B b = new B();
try {
   Class c = Class.forName("C");
}catch(ClassNotFoundException cnfe){
    System.out.println(" classe pas trouvée : "+cnfe.getMessage() )
}

Provoquent les sorties : 

 chargement de A
 chargement de B
 chargement de C

2 Obtenir une référence à l'instance de Class   

  1. A partir d'une classe  en utilisant le littéral class:
    Class cA1 = A.class ;
  2. A partir du nom d'une classe ( sans le .class, mais avec le(s) paquetage(s) ) : 
    Class cA2 = Class.forName("A");
  3. A partir d'une instance de la classe :
    A a = new A() ;
    Class cA = a.getClass() ;
  4. Pour une classe générique :
    class A<T, V>{
       // ...
    }
    
    A <String, Integer> a = new A<String, Integer> () ;
    Class<? extends A> cA = a.getClass() ;

3 La méthode getName()

La méthode getName() retourne le nom de la classe. Ce nom est construit de la façon suivante pour les tableaux :

Le programme
Les résultats
Object[][] to = new Object[1][2];
Object o = new Object();
int [] ti = {1, 2, 3};
System.out.println(to.getClass().getName());
System.out.println(o.getClass().getName());
System.out.println(ti.getClass().getName());
[[Ljava.lang.Object;
java.lang.Object
[I

4 Obtenir des informations sur une classe : introspection

Les méthodes de la classe Class permettent de connaître : 

Exemple : 

classA <T extends Integer, V> implements Comparable<T> {
   public T aDeA;
   public A(){}
   public void fDeA(){}
   public int compareTo(T o) {
      return 0;
   }
}

class B<T extends Integer, V> extends A<T, V> implements Cloneable, Comparable<T>{
   public int aDeB;
   private int prive;
   public B(Integer a) {
      aDeB  = a;
   }
   public B(){}
   public String toString(){
      return "B : "+aDeB;
   }

   public void setADeB(T d) {
      aDeB = d;
   }
   public void fDeB(){}
}


Le code suivant : 

   B b = new B();
   Class cB = b.getClass();
   System.out.println("   les attributs de : "+ cB.getName());
      Field fs[] =  cB.getFields();
      if( fs.length!=0)
         for( int i = 0; i < fs.length; ++i){
            tem.out.println(fs[i]);
   }
   else System.out.println(" pas d'attributs");
    System.out.println("   les méthodes de : "+ cB.getName());
      Method ms[] = cB.getMethods();
      if( ms.length!=0)
         for( int i = 0; i <  ms.length; ++i){
            System.out.println(ms[i]);
         }
         else System.out.println(" pas de méthode");
         
   System.out.println("   les constructeurs de : "+ cB.getName());
      Constructor cs[] = cB.getConstructors();
      if ( cs.length!=0)
         for( int i = 0; i <  cs.length; ++i){
            System.out.println(cs[i]);
         }
      else System.out.println(" pas de constructeur");
    System.out.println("   les interfaces de : "+ cB.getName());
      Class is[] = cB.getInterfaces();
      if( is.length!=0)
         for ( int i = 0; i <  is.length; ++i){
            System.out.println(is[i]);
         }
      else System.out.println(" pas d'interface");
 
   System.out.println(" nom de la classe mère : "+cB.getSuperclass().getName());
   
   Type ts = cB.getGenericSuperclass();
   System.out.println(" nom de la classe mère générique : "+ts.toString());
 
   Type[] tis = cB.getGenericInterfaces();
   System.out.println(" nom des interfaces génériques implémentées : ");
   for( int i = 0; i <  tis.length; ++i)
       System.out.println("   "+tis[i]);

Donne les sorties suivantes : 

   les attributs de : B
public int B.aDeB
public java.lang.Integer A.aDeA
   les méthodes de : B
public void B.setADeB(java.lang.Integer)
public void B.fDeB()
public java.lang.String B.toString()
public void A.fDeA()
public static void A.main(java.lang.String[])
public int A.compareTo(java.lang.Integer)
public int A.compareTo(java.lang.Object)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public boolean java.lang.Object.equals(java.lang.Object)
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
   les constructeurs de : B
public B(java.lang.Integer)
   les interfaces de : B
interface java.lang.Cloneable
interface java.lang.Comparable
 nom de la classe mère : A
 nom de la classe mère générique : A<T, V>
 nom des interfaces génériques implémentées : 
   interface java.lang.Cloneable
   java.lang.Comparable<T>

5 Aller plus loin ...

5.1 Création d'instance

On peut créer une instance d'une classe, en ne connaissant que son nom :

try{ 
   Class<?> cB = Class.forName ("B");
   // Récupération du constructeur prenant en paramètre un Integer
   Class<?>  ci = Class.forName ("java.lang.Integer");
   Class [] parametres = { ci };
   Constructor constructeur =  cB.getConstructor (parametres);
   // Création d'un objet de la classe B
   Object o = constructeur.newInstance (new Object [] {12});
   System.out.println(o);
}catch (ClassNotFoundException e){
   System.out.println(" La classe "+e.getMessage()+" n'existe pas");
}catch (NoSuchMethodException e){
   System.out.println("Le constructeur "+e.getMessage()+" n'existe pas");
}catch (InstantiationException e){
   System.out.println("La classe est abstraite ou est une interface ");
}catch (IllegalAccessException e){
   System.out.println("La classe n'est pas accessible");
}catch (java.lang.reflect.InvocationTargetException e){
   System.out.println(e.getMessage());
}

5.2 Invocation de méthode

Le code suivant permet d'appeler la méthode setADeB et la méthode toString pour l'objet o créé précédemment : 

// appel de setADeB
Class [] typeParametre = {Integer.class};
Object[] parametre = {15};
Method m = cB.getMethod("setADeB", typeParametre);
m.invoke(o, parametre);
// appel de toString
m = cB.getMethod("toString", (Class<?>[])null);
System.out.println(m.invoke(o, (Object[])null));

5.3 Modification d'un attribut privé

try {
   // getDeclaradField pour obtenir un attribut privé
   Field f = cB.getDeclaredField("prive");
   f.setAccessible(true);
   System.out.println("prive avant modification : "+f.getInt(o));
   f.setInt(o, 123);
   System.out.println("prive après modification : "+f.getInt(o));
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
}

5.4 Programmation de la commande javap

La commande javap permet d'afficher les informations contenues dans les fichiers de classes. Quelques unes des options sont :

Le code suivant permet de simuler la commande javap avec la seule option -private

public class Javap {
   public static String modificateurs(int mod) {
      String res = "";
      if (Modifier.isPublic(mod))      res += " public";
      if (Modifier.isPrivate(mod))     res += " private";
      if (Modifier.isProtected(mod))   res += " protected";
      if (Modifier.isStatic(mod))      res += " static";
      if (Modifier.isAbstract(mod))    res += " abstract";
      if (Modifier.isFinal(mod))       res += " final";
      if (Modifier.isNative(mod))      res += " native";
      if (Modifier.isTransient(mod))   res += " transient";
      if (Modifier.isSynchronized(mod))res += " synchronized";
      return res.substring(1);
   }

    public static void main(String[] args) {
      if (args.length == 0) {
         System.out.println("pas d'arguments ...");
         return;
      }
      for (int k = 0; k < args.length; ++k) {
         String nom = args[k];
         try {
            Class cl = Class.forName(nom);
            // les modifieurs de la classe 
            String res = modificateurs(cl.getModifiers()) + " class "+ cl.getName();
            // la super classe
            res += " extends " + cl.getSuperclass().getName();
            // les interfaces implémentées
            Class is[] = cl.getInterfaces();
            if (is.length != 0) {
               res += " implements " + is[0].getName();
               for (int i = 1; i < is.length; ++i)
                  res += ", " + is[i].getName();
            }
            res += "{\n";
            // les attributs
            Field fs[] = cl.getDeclaredFields();
            if (fs.length != 0)
               for (int i = 0; i < fs.length; ++i)
                  res += "   " + modificateurs(fs[i].getModifiers())
                        + " " + fs[i].getType() + " " + fs[i].getName()+ ";\n";
            // les constructeurs
            Constructor cs[] = cl.getDeclaredConstructors();
            if (cs.length != 0)
               for (int i = 0; i < cs.length; ++i) {
                  res += "   " + modificateurs(cs[i].getModifiers())
                        + " " + cs[i].getName() + "(";
                  Class<?>[] params = cs[i].getParameterTypes();
                  if (params.length != 0) {
                     res += params[0].getName();
                     for (int j = 1; j < params.length; ++j)
                        res += ", " + params[j].getName();
                  }
                  res += ");\n";
               }
            // les méthodes
            Method ms[] = cl.getDeclaredMethods();
            if (ms.length != 0)
               for (int i = 0; i < ms.length; ++i) {
                  res += "   " + modificateurs(ms[i].getModifiers())
                        + " " + ms[i].getReturnType() + " "
                        + ms[i].getName() + "(";
                  Class<?>[] params = ms[i].getParameterTypes();
                  if (params.length != 0) {
                     res += params[0].getName();
                     for (int j = 1; j < params.length; ++j)
                        res += ", " + params[j].getName();
                  }
                  res += ");\n";
               }
            res += "}";
            System.out.println(res);
         } catch (ClassNotFoundException e) {
            System.out.println("La classe " + nom + " n'existe pas !");
         }
      }
   }

}


haut de la page