Oui, il existe une optimisation pour réduire les coûts de Reflection, bien qu'elle soit implémentée principalement dans la bibliothèque de classes plutôt que dans la JVM.
Avant Java 1.4 Method.invoke
travaillait via un appel JNI à l'exécution VM. Chaque invocation nécessitait au moins deux transitions de Java vers Native et de retour vers Java. L'environnement d'exécution de la machine virtuelle analysait une signature de méthode, vérifiait que les types d'arguments passés étaient corrects, effectuait un boxing/unboxing et construisait un nouveau cadre Java pour une méthode appelée. Tout cela était plutôt lent.
Depuis Java 1.4 Method.invoke
utilise la génération dynamique de bytecode si une méthode est appelée plus de 15 fois (configurable via sun.reflect.inflationThreshold
propriété système). Une classe Java spéciale chargée d'appeler la méthode particulière donnée est construite en exécution. Cette classe implémente sun.reflect.MethodAccessor auxquels java.lang.reflect.Method
appelle les délégués.
L'approche avec la génération de bytecode dynamique est beaucoup plus rapide car il
- ne souffre pas de frais généraux JNI;
- n'a pas besoin d'analyser la signature de méthode à chaque fois, car chaque méthode appelée via Reflection possède son propre MethodAccessor;
- peut être davantage optimisé, par ex. ces MethodAccessors peuvent bénéficier de toutes les optimisations JIT régulières comme inline, propagation constante, autoboxing élimination etc.
Notez que cette optimisation est mis en œuvre principalement dans Java code sans l'aide JVM. La seule chose que fait la machine virtuelle HotSpot pour rendre cette optimisation possible est de sauter la vérification du bytecode pour de tels MethodAccessors générés. Sinon, le vérificateur ne permettrait pas, par exemple, d'appeler des méthodes privées.
Peut-être que cela a quelque chose à voir avec ['MethodHandles.Lookup # unreflect()'] (http://docs.oracle.com/javase/8/docs/api/java/lang/invoke/MethodHandles.Lookup. html # unreflect-java.lang.reflect.Method-)? – fge