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.
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;".
Retourne la représentation textuelle d'une classe.public static native Class forName (String className) throws ClassNotFoundExceptionretournent les chaînes
(new Object[3]).getClass().getName() (new Date())..getClass().getName()
"[Ljava.lang.Object;" "java.util.Date"
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.public Field[] getMethods () throws SecurityException
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]);
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:
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() }
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) }
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:
Il faut alors passer par la méthode newInstance:
Vector v = new Vector();
Il reste toutefois un point à éclaircir: comment créer dynamiquement un objet en utilisant un constructeur avec arguments:
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); }
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.
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(...) { ...} ... }
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.
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
La version de jdk1.2 fournit pour ce package :
Les Classes:
AccessibleObject:
Array:
Constructor:
Field:
Method:
Modifier:
ReflectPermission:
Les interfaces:
Membre:
A TERMINER