Capacité du langage à se décrire et se manipuler
NB : Il s'agit de reflection comme "refléter", et non pas de réfexion comme "réfléchir".
Java permet de manipuler toute classe que la JVM peut charger en mémoire : nos classes, les classes de l'api java, les classes des libs chargées ...
ReflectiveOperationException
Exception à utiliser lorsqu'on travaille avec la reflection.public class java.lang.ReflectiveOperationException extends Exception implements SerializableDirect Known Subclasses:
ClassNotFoundException
IllegalAccessException
InstantiationException
InvocationTargetException
NoSuchFieldException
NoSuchMethodException
Analyser une classe
Les classes étant le type le plus utilisé en java,java.lang.Class
(qui représente une classe) est une classe centrale de la reflection.
On peut connaître la
Class
de tout objet via getClass()
, définie dans java.lang.Object
.
Création
Class.forName()
Manière habituelle de créer un objet de typeClass
.
Class<?> c = Class.forName("java.util.Scanner");
Suffixe .class
Raccourci syntaxique : un type java suivi de.class
représente une instance de java.lang.Class
.
Class<?> c = String[].class; // Describes the array type String[] Class<?> c = Runnable.class; // Describes the Runnable interface Class<?> c = int.class; // Describes the int type Class<?> c = void.class; // Describes the void type
Nom de la classe
String getName() // [Ljava.lang.String; => nom bizarre String getCanonicalName() // java.lang.String[] => nom lisible String getSimpleName() // String[] String getTypeName() // java.lang.String[] String toString() // class [Ljava.lang.String; String toGenericString() // public abstract final class [Ljava.lang.String;
Autres infos
Class<? super T> getSuperclass() Class<?>[] getInterfaces() Package getPackage() int getModifiers()
boolean isPrimitive() boolean isArray() boolean isEnum() boolean isAnnotation() boolean isMemberClass() boolean isLocalClass() boolean isAnonymousClass()
Class<?> getDeclaringClass() Class<?> getEnclosingClass() Constructor getEnclosingConstructor() Method getEnclosingMethod()Tableau des champs, méthodes et constructeurs publics de la classe
Incluent ceux hérités des superclasses.
Constructor<?>[] getConstructors() Field[] getFields() Method[] getMethods()Tableau des champs, méthodes et constructeurs déclarés dans la classe ;
renvoie les membres private, package, protected.
Ne renvoie pas les membres des super-classes.
Constructor<?>[] getDeclaredConstructors() Field[] getDeclaredFields() Method[] getDeclaredMethods()
Exemple : lister les méthodes d'une classe
Class<?> c = Class.forName("java.lang.reflect.Method"); System.out.println("===== Methods of : " + c.getCanonicalName() + " ====="); for(Method m : c.getDeclaredMethods()){ System.out.println(); String modifiers = Modifier.toString(m.getModifiers()); System.out.print(modifiers == "" ? "void" : modifiers); System.out.print(" " + m.getReturnType().getSimpleName()); System.out.print(" " + m.getName()); // params System.out.print("("); List<String> params = new ArrayList<>(); for(Parameter param : m.getParameters()){ params.add(param.getType().getSimpleName()); } System.out.print(String.join(", ", params)); System.out.print(")"); } System.out.println();(code dans ClassMethods.java)
java ClassMethods
===== Methods of : java.lang.reflect.Method ===== public transient Object invoke(Object, Object[]) public boolean equals(Object) public String toString() etc.
Détails sur les membres d'une classe
Les classesField
, Method
, and Constructor
de java.lang.reflect
décrivent les champs, méthodes et constructeurs d'une classe.
Ces 3 classes ont une méthode
getName()
qui retourne le nom du membre.
java.lang.reflect.Method
Pour obtenir toutes sortes d'informations sur les méthodes, par exemple :
Class<?> getDeclaringClass() int getModifiers() int getParameterCount() Class<?>[] getParameterTypes() Class<?> getReturnType()
getModifiers()
renvoie un entier exprimant les modifiers de la méthode (public, abstract final etc.).
Utilisable avec les méthodes statiques de la classe
java.lang.reflect.Modifiers
:
isAbstract(int mod) isPublic(int mod) isFinal(int mod) isStatic(int mod) isInterface(int mod) isStrict(int mod) isNative(int mod) isSynchronized(int mod) isPrivate(int mod) isTransient(int mod) isProtected(int mod) isVolatile(int mod)
Travailler avec des instances
Inspecter un objet
La méthodeget()
de Field
permet de connaître la valeur d'un champ.
Object obj = new String("toto"); try{ for (Field f : obj.getClass().getDeclaredFields()) { f.setAccessible(true); Object value = f.get(obj); System.out.println(f.getName() + ":" + value); } } catch(ReflectiveOperationException e){ e.printStackTrace(); }(code dans InspectObject.java)
Invoquer une méthode
Dans la classeMethod
, on utilise la méthode public Object invoke(Object obj, Object... args)
.
Invoque la méthode représentée par cet objet (mettre
null
pour des variables statiques).
import java.lang.reflect.*; class Person{ private String name; public Person(String name){ this.name = name; } public String getName(){ return name; } public void setName(String name){ this.name = name; } } public class InvokeMethod { public static void main(String[] args) { try{ Person p = new Person("toto"); Method m; m = p.getClass().getMethod("getName"); Object name = m.invoke(p); System.out.println(name); m = p.getClass().getMethod("setName", String.class); m.invoke(p, "titi"); System.out.println(p.getName()); } catch(ReflectiveOperationException e){ e.printStackTrace(); } } }(code dans InvokeMethod.java)
Construire un objet
Exemple : invoquer le constructeur dePerson
qui prend une String
en paramètre.
Class> c = Person.class; Constructor constr = c.getConstructor(String.class); // varargs Object obj = constr.newInstance("tutu"); System.out.println(((Person)obj).getName());(code aussi ans InvokeMethod.java)
Attention, bien utiliser
Constructor.newInstance()
et non pas Class.newInstance()
(a été déprécié en java 9).
Divers
Infos sur le fichier .java courant
Equivalent java de php pour :PHP Java ------------------------- Current line number of the file __LINE__ System.out.println(Thread.currentThread().getStackTrace()[1].getLineNumber()); Full path and filename of current file __FILE__ ???? Directory of current file __DIR__ this.getClass().getProtectionDomain().getCodeSource().getLocation().toExternalForm() Current class name __CLASS__ this.getClass().getCanonicalName() Current method name __METHOD__ ???? Current namespace __NAMESPACE__ this.getClass().getPackage().getName()
Exercice / TD
Utilisation de la reflection avec le pattern Command