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