present (sb for a job etc)
Each class has aClass object that contains information about the class. When a new class is compiled, a .class file with the same name is produced, the contents of which hold the Class object.
Class loading is equivalent to loading Class objects. Classes are dynamically loaded into the JVM the first time they are used. You can control the loading of classes by using (""), a method that returns a Class object.
Reflection can provide class information at runtime, and the class can be loaded in only at runtime, even if the .class does not exist at compile time.
Classes and reflections are supported together. The class library consists of three main classes.
-
Field
-
Method
-
Constructor
The Java Reflection Mechanism is the mechanism by which theThe ability to dynamically obtain information about a class at runtime and be able to manipulate the properties and methods of that classThe Java reflection mechanism allows programs to manipulate their own properties and methods at runtime with the help of the Class class API, which greatly enhances the flexibility and extensibility of Java.
advantages and disadvantages
Pros:
- Improved program flexibility: Class information can be accessed and manipulated at runtime, giving the program better flexibility and extensibility.
- Reduced code duplication: The ability to dynamically obtain and manipulate class information reduces code duplication.
- Improved maintainability of the program: the structure of the program can be made more clear and concise, improving the maintainability of the program.
Drawbacks:
- Lower performance: Java reflection mechanism is through the run-time dynamic acquisition and manipulation of class information, lower performance.
- Security issues: Java reflection mechanism can access and manipulate all the information of the class, there are security issues.
public void test2() {
long start = ();
for (int i = 0; i < 10000000; i++) {
getAuthor(); //running time15
// getAuthorByReflect();//running time4378
}
long end = ();
("running time:" + (end - start));
}
How to get
//1. Accessed via class.class
class s = ;
//2. Get by name
class s = (SubjectService);
//3. Get by object.getclass
class s = ();
//4. Get it through the class loader
ClassLoader classLoader = ();
Class s = ("Full class name");
Compare the difference between the four ways of fetching? Fetching through the class loader is not commonly used and will not be compared here.
- Class name.class: The JVM will use the class loader, load the class into memory (provided: the class is not already loaded into memory), do not do the initialization of the class, and return the object of the Class.
- ("class name string"): loads the class and does a static initialization of the class, returning the object of Class.
- Instance object.getClass(): static initialization, non-static initialization of the class; return the object that references the object that is really referred to at runtime (the reference of the child object will be assigned to the parent object in the reference variable) belongs to the class of the Class.
application scenario
- Framework Design: In framework design, it is often necessary to use reflection techniques to decouple and make the framework scalable and flexible.
- Unit Testing: In unit testing, we can use reflection techniques to access private or protected class members to make testing more comprehensive.
- Dynamic Proxy: Using reflection techniques you can create dynamic proxy objects that can proxy any object that implements an interface at runtime to achieve AOP and other features.
- Serialization and deserialization : Many Java serialization and deserialization tools are based on the Java reflection mechanism implementation , such as Java's ObjectInputStream and ObjectOutputStream.
Java reflection technology can be applied in many scenarios, especially in the framework design and componentized development, reflection technology can improve the flexibility and scalability of the code, reduce code coupling, and simplify the code writing. However, the reflection mechanism also increases the complexity of the program, so it must be used with caution.
Implementation process
public class HelloReflect {
public static void main(String[] args) {
try {
// 1. Implementations using external configurations,Perform dynamic loading of classes
TempFunctionTest test = (TempFunctionTest)("").newInstance();
("call directly");
// 2. Function name according to configuration,Making method calls(No need for generic interface abstractions)
Object t2 = new TempFunctionTest();
Method method = ().getDeclaredMethod("sayHello", );
(test, "method invoke");
} catch (ClassNotFoundException e) {
();
} catch (InstantiationException e) {
();
} catch (IllegalAccessException e) {
();
} catch (NoSuchMethodException e ) {
();
} catch (InvocationTargetException e) {
();
}
}
public void sayHello(String word) {
("hello," + word);
}
}
Reflection to get class instances
Getting class information
The first call is to the static method of the class to get the class information.
@CallerSensitive
public static Class <? > forName(String className) throws ClassNotFoundException {
// Get the current classLoader by getting information about the incoming class through reflection.
Class <? > caller = (); // Call the native method to get the current classLoader.
// Call the native method to get the class information.
return forName0(className, true, (caller), caller); }
}
The forName() reflection to get class information doesn't leave the implementation to java, but to jvm to load.
The main thing is to get the ClassLoader first, then call the native method to get the information and load the class as a callback .
Finally, jvm calls back to ClassLoader for class loading.
public Class <? > loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
//
public Class <? > loadClass(String var1, boolean var2) throws ClassNotFoundException {
int var3 = (46);
if (var3 != -1) {
SecurityManager var4 = ();
if (var4 != null) {
((0, var3));
}
}
if ((var1)) {
Class var5 = (var1);
if (var5 != null) {
if (var2) {
(var5);
}
return var5;
} else {
throw new ClassNotFoundException(var1);
}
} else {
return (var1, var2);
}
}
//
protected Class <? > loadClass(String name, boolean resolve)
throws ClassNotFoundException {
// Get the lock first.
synchronized(getClassLoadingLock(name)) {
// First, check if the class has already been loaded
// If it's already loaded,You won't have to load it again.
Class <? > c = findLoadedClass(name);
if (c == null) {
long t0 = ();
try {
// Parental Delegation Loading
if (parent != null) {
c = (name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
// When the parent class is not loaded,And then load it yourself.
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = ();
c = findClass(name);
// this is the defining class loader; record the stats
().addTime(t1 - t0);
().addElapsedTimeFrom(t1);
().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
protected Object getClassLoadingLock(String className) {
Object lock = this;
if (parallelLockMap != null) {
// utilization ConcurrentHashMapto save the lock
Object newLock = new Object();
lock = (className, newLock);
if (lock == null) {
lock = newLock;
}
}
return lock;
}
protected final Class <? > findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}
Implementation of newInstance()
Here's a look at how newInstance() is implemented.
// First of all, I'm sure.
@CallerSensitive
public T newInstance() throws InstantiationException, IllegalAccessException {
if (() != null) {
//If a security manager exists,then call checkMemberAccess Methods to conduct security checks,to ensure that the caller has sufficient privileges to create the instance。
checkMemberAccess(, (), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
//in the event that cachedConstructor empty,then look for the unparameterized constructor。
if (cachedConstructor == null) {
if (this == ) {
// It is not allowed to call Class (used form a nominal expression) newInstance() methodologies
throw new IllegalAccessException(
"Can not call newInstance() on the Class for "
);
}
try {
// Get the unparameterized constructor
Class <? > [] empty = {};
//getConstructor0 methodologies获取无参构造函数,and set it to be accessible(setAccessible(true))。
final Constructor < T > c = getConstructor0(empty, );
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
(
new < Void > () {
public Void run() {
(true);
return null;
}
});
//将获取到(used form a nominal expression)构造函数缓存起来,so that the next call can be made directly using the。
cachedConstructor = c;
} catch (NoSuchMethodException e) {
//in the event that不存在无参构造函数,Then it throws the InstantiationException
throw (InstantiationException) new InstantiationException(getName()).initCause(e);
}
}
//获取缓存(used form a nominal expression)构造函数,and check its modifiers。
Constructor < T > tmpConstructor = cachedConstructor;
// Security check (same as in )
int modifiers = ();
if (!(this, modifiers)) {
//in the event that快速检查不通过,then get the caller class,invoke methodologies进行更详细(used form a nominal expression)检查,and cache the caller class。
Class <? > caller = ();
if (newInstanceCallerCache != caller) {
(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
// Calling an unparameterized constructor
return ((Object[]) null);
} catch (InvocationTargetException e) {
().throwException(());
// Not reached
return null;
}
}
newInstance() does three main things:
- Permission checking, if not passed directly throw an exception;
- Finds the unparameterized constructor and caches it;
- Calls the unparameterized constructor of the concrete method, generates the instance and returns it;
Get Constructor
Here's how to get the constructor:
private Constructor < T > getConstructor0(Class <? > [] parameterTypes, int which) throws NoSuchMethodException {
// Get all constructors
Constructor < T > [] constructors = privateGetDeclaredConstructors((which == ));
for (Constructor < T > constructor: constructors) {
if (arrayContentsEq(parameterTypes,
())) {
return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
getConstructor0() gets the matching constructor; three steps:
- Get all the constructors first, and then by doing a parameter type comparison;
- When a match is found, a copy of the constructor is returned via ReflectionFactory;
- Otherwise throws NoSuchMethodException.
// Get all the constructor methods of the current class,pass (a bill or inspection etc)jvmOr cache
// Returns an array of "root" constructors. These Constructor
// objects must NOT be propagated to the outside world, but must
// instead be copied via .
private Constructor < T > [] privateGetDeclaredConstructors(boolean publicOnly) {
checkInitted();
Constructor < T > [] res;
// invocations reflectionData(), Getting Saved Information,Saving with soft references,Thus, not enough memory can be reclaimed
ReflectionData < T > rd = reflectionData();
if (rd != null) {
res = publicOnly ? : ;
// Cache exists,then it returns directly to the
if (res != null) return res;
}
// No cached value available; request value from VM
if (isInterface()) {@
SuppressWarnings("unchecked")
Constructor < T > [] temporaryRes = (Constructor < T > []) new Constructor <? > [0];
res = temporaryRes;
} else {
// utilizationnativemethod fromjvmGet Constructor
res = getDeclaredConstructors0(publicOnly);
}
if (rd != null) {
// ultimate,will depart fromjvmThe contents of the readings in the,store in cache
if (publicOnly) {
= res;
} else {
= res;
}
}
return res;
}
// Lazily create and cache ReflectionData
private ReflectionData < T > reflectionData() {
SoftReference < ReflectionData < T >> reflectionData = ;
int classRedefinedCount = ;
ReflectionData < T > rd;
if (useCaches &&
reflectionData != null &&
(rd = ()) != null &&
== classRedefinedCount) {
return rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
return newReflectionData(reflectionData, classRedefinedCount);
}
// New Cache Creation,Save Reflections
private ReflectionData < T > newReflectionData(SoftReference < ReflectionData < T >> oldReflectionData,
int classRedefinedCount) {
if (!useCaches) return null;
// utilizationcasEnsuring thread safety for updates,So reflection is thread-safe
while (true) {
ReflectionData < T > rd = new ReflectionData < > (classRedefinedCount);
// try to CAS it...
if ((this, oldReflectionData, new SoftReference < > (rd))) {
return rd;
}
// 先utilizationCASupdate,如果update成功,then immediately return the,否则测查当前已被其他线程update的情况,如果和自己想要update的状态一致,Then it's a success.
oldReflectionData = ;
classRedefinedCount = ;
if (oldReflectionData != null &&
(rd = ()) != null &&
== classRedefinedCount) {
return rd;
}
}
}
As above, privateGetDeclaredConstructors(), get all constructors main step;
- Try getting it from the cache first;
- If the cache is not available, it is refetched from the jvm and stored in the cache, which is saved using soft references to ensure that memory is available;
Alternatively, use relactionData() for cache saving; the data structure of ReflectionData is as follows.
// reflection data that might get invalidated when JVM TI RedefineClasses() is called
private static class ReflectionData < T > {
volatile Field[] declaredFields;
volatile Field[] publicFields;
volatile Method[] declaredMethods;
volatile Method[] publicMethods;
volatile Constructor < T > [] declaredConstructors;
volatile Constructor < T > [] publicConstructors;
// Intermediate results for getFields and getMethods
volatile Field[] declaredPublicFields;
volatile Method[] declaredPublicMethods;
volatile Class <? > [] interfaces;
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;
ReflectionData(int redefinedCount) {
= redefinedCount;
}
}
One of the points, there is a point, is how to compare the construction is to find the constructor, in fact, it is to compare the type completion is equal to the end, there is a not equal to return false.
private static boolean arrayContentsEq(Object[] a1, Object[] a2) {
if (a1 == null) {
return a2 == null || == 0;
}
if (a2 == null) {
return == 0;
}
if ( != ) {
return false;
}
for (int i = 0; i < ; i++) {
if (a1[i] != a2[i]) {
return false;
}
}
return true;
}
//
/** Makes a copy of the passed constructor. The returned
constructor is a "child" of the passed one; see the comments
in for details. */
public < T > Constructor < T > copyConstructor(Constructor < T > arg) {
return langReflectAccess().copyConstructor(arg);
}
// , copy It's actually the newnewan Constructor (after a verb, indicates coming out, completion of an action, or ability discern or detect)
Constructor < T > copy() {
// This routine enables sharing of ConstructorAccessor objects
// among Constructor objects which refer to the same underlying
// method in the VM. (All of this contortion is only necessary
// because of the "accessibility" bit in AccessibleObject,
// which implicitly requires that new
// objects be fabricated for each reflective call on Class
// objects.)
if ( != null)
throw new IllegalArgumentException("Can not copy a non-root Constructor");
Constructor < T > res = new Constructor < > (clazz,
parameterTypes,
exceptionTypes, modifiers, slot,
signature,
annotations,
parameterAnnotations);
// root point to the current constructor
= this;
// Might as well eagerly propagate this if already present
= constructorAccessor;
return res;
}
Above, we get the Constructor.
The next step is simply to call newInstance() of the corresponding constructor, which returns the instance.
// return ((Object[])null);
//
@CallerSensitive
public T newInstance(Object...initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!override) {
if (!(clazz, modifiers)) {
Class <? > caller = ();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((() & ) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}@
SuppressWarnings("unchecked")
T inst = (T) (initargs);
return inst;
}
//
public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException {
return (args);
}
//
public Object newInstance(Object[] args) throws InstantiationException, IllegalArgumentException, InvocationTargetException {
// We can't inflate a constructor belonging to a vm-anonymous class
// because that kind of class can't be referred to by name, hence can't
// be found from the generated bytecode.
if (++numInvocations > () && !(())) {
ConstructorAccessorImpl acc = (ConstructorAccessorImpl)
new MethodAccessorGenerator().
generateConstructor((),
(),
(),
());
(acc);
}
// call (programming)nativemethodologies,进行call (programming) constructor
return newInstance0(c, args);
}
After returning the instance of the constructor, you can use the interface or method to call the instance function by type conversion according to the external.
Difference between the two ways of getting class instances
- (): only parameterless constructors, i.e., default constructors, can be called; and the called constructor is required to be visible, i.e., it must be of type public.
- (): you can call any constructor constructor according to the parameters passed in; you can call private constructors.
The () method was deprecated after JDK9, see this article for detailsDeprecating class-newinstance
Reflection Acquisition Method
Get Method
//
@CallerSensitive
public Method getDeclaredMethod(String name, Class <? > ...parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(, (), true);
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}
Ignoring the first check permission, there are only two actions left.
-
Get a list of all methods;
-
Based on the name of the method and the list of methods, select the method that meets the requirements;
-
Throws an exception if the corresponding method is not found, otherwise returns the corresponding method;
So, let's first look at how to get all the methods declared by the class
// Returns an array of "root" methods. These Method objects must NOT
// be propagated to the outside world, but must instead be copied
// via .
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
Method[] res;
ReflectionData < T > rd = reflectionData();
if (rd != null) {
res = publicOnly ? : ;
if (res != null) return res;
}
// No cached value available; request value from VM
res = (this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
= res;
} else {
= res;
}
}
return res;
}
It's very similar, and very similar to getting all the constructors, in that it's all about getting the method from the cache first, and if it's not there, getting it from the jvm.
The difference is that the list of methods needs to be filtered ; of course, later on, it seems that this method is not something we would normally use.
//
public static Method[] filterMethods(Class <? > containingClass, Method[] methods) {
if (methodFilterMap == null) {
// Bootstrapping
return methods;
}
return (Method[]) filter(methods, (containingClass));
}
// You can filter the specified methods,Generally empty,If you want to specify a filter,can be invoked registerMethodsToFilter(), or...
private static Member[] filter(Member[] members, String[] filteredNames) {
if ((filteredNames == null) || ( == 0)) {
return members;
}
int numNewMembers = 0;
for (Member member: members) {
boolean shouldSkip = false;
for (String filteredName: filteredNames) {
if (() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
++numNewMembers;
}
}
Member[] newMembers =
(Member[]) (members[0].getClass(), numNewMembers);
int destIdx = 0;
for (Member member: members) {
boolean shouldSkip = false;
for (String filteredName: filteredNames) {
if (() == filteredName) {
shouldSkip = true;
break;
}
}
if (!shouldSkip) {
newMembers[destIdx++] = member;
}
}
return newMembers;
}
Filtering specified methods by method name and parameter type returns the
private static Method searchMethods(Method[] methods, String name, Class <? > [] parameterTypes) {
Method res = null;
// Using the Constant Pool,Avoid duplicate creationString
String internedName = ();
for (int i = 0; i < ; i++) {
Method m = methods[i];
if (() == internedName && arrayContentsEq(parameterTypes, ())
&& (res == null || ().isAssignableFrom(())))
res = m;
}
return (res == null ? res : getReflectionFactory().copyMethod(res));
}
The general idea reads like a match to the method name, and then a match to the parameter types to make it work.
-
But as you can see, matching to a method doesn't exit the for loop, it continues.
-
Here is the subclass that matches the most accurate subclass to be returned (optimal match)
-
Finally, it is returned by the ReflectionFactory, copy method.
Calling the () method
@CallerSensitive
public Object invoke(Object obj, Object...args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
if (!override) {
if (!(clazz, modifiers)) {
Class <? > caller = ();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return (obj, args);
}
When invoke, it is called through MethodAccessor, which is an interface that calls acquireMethodAccessor() for the first time to create a new one.
// probably make the implementation more scalable.
private MethodAccessor acquireMethodAccessor() {
// First check to see if one has been created yet, and take it
// if so
MethodAccessor tmp = null;
if (root != null) tmp = ();
if (tmp != null) {
// When a cache exists,deposit (e.g. in a bank account) methodAccessor,Otherwise, call ReflectionFactory Create a new MethodAccessor
methodAccessor = tmp;
} else {
// Otherwise fabricate one and propagate it up to the root
tmp = (this);
setMethodAccessor(tmp);
}
return tmp;
}
//
public MethodAccessor newMethodAccessor(Method method) {
checkInitted();
if (noInflation && !(())) {
return new MethodAccessorGenerator().
generateMethod((),
(),
(),
(),
(),
());
} else {
NativeMethodAccessorImpl acc =
new NativeMethodAccessorImpl(method);
DelegatingMethodAccessorImpl res =
new DelegatingMethodAccessorImpl(acc);
(res);
return res;
}
}
Two Accessor details:
//NativeMethodAccessorImpl / DelegatingMethodAccessorImpl
class NativeMethodAccessorImpl extends MethodAccessorImpl {
private final Method method;
private DelegatingMethodAccessorImpl parent;
private int numInvocations;
NativeMethodAccessorImpl(Method method) {
= method;
}
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
// We can't inflate methods belonging to vm-anonymous classes because
// that kind of class can't be referred to by name, hence can't be
// found from the generated bytecode.
if (++numInvocations > ()
&& !(())) {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod((),
(),
(),
(),
(),
());
(acc);
}
return invoke0(method, obj, args);
}
void setParent(DelegatingMethodAccessorImpl parent) {
= parent;
}
private static native Object invoke0(Method m, Object obj, Object[] args);
}
class DelegatingMethodAccessorImpl extends MethodAccessorImpl {
private MethodAccessorImpl delegate;
DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) {
setDelegate(delegate);
}
public Object invoke(Object obj, Object[] args)
throws IllegalArgumentException, InvocationTargetException
{
return (obj, args);
}
void setDelegate(MethodAccessorImpl delegate) {
= delegate;
}
}
Perform (obj, args); call (); call
It is finally delegated to (), i.e:
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException {
// We can't inflate methods belonging to vm-anonymous classes because
// that kind of class can't be referred to by name, hence can't be
// found from the generated bytecode.
if (++numInvocations > () && !(())) {
MethodAccessorImpl acc = (MethodAccessorImpl)
new MethodAccessorGenerator().
generateMethod((),
(),
(),
(),
(),
());
(acc);
}
// invoke0 It's a... native methodologies,leave it (to sb)jvm进行调用业务methodologies。This completes the reflective invocation functionality。
return invoke0(method, obj, args);
}
where generateMethod() is the method that generates the concrete class:
/** This routine is not thread-safe */
public MethodAccessor generateMethod(Class <? > declaringClass,
String name,
Class <? > [] parameterTypes,
Class <? > returnType,
Class <? > [] checkedExceptions,
int modifiers) {
return (MethodAccessor) generate(declaringClass,
name,
parameterTypes,
returnType,
checkedExceptions,
modifiers,
false,
false,
null);
}
generate() poke for details.
/** This routine is not thread-safe */
private MagicAccessorImpl generate(final Class <? > declaringClass,
String name,
Class <? > [] parameterTypes,
Class <? > returnType,
Class <? > [] checkedExceptions,
int modifiers,
boolean isConstructor,
boolean forSerialization,
Class <? > serializationTargetClass) {
ByteVector vec = ();
asm = new ClassFileAssembler(vec);
= declaringClass;
= parameterTypes;
= returnType;
= modifiers;
= isConstructor;
= forSerialization;
();
// Constant pool entries:
// ( * = Boxing information: optional)
// (+ = Shared entries provided by AccessorGenerator)
// (^ = Only present if generating SerializationConstructorAccessor)
// [UTF-8] [This class's name]
// [CONSTANT_Class_info] for above
// [UTF-8] "sun/reflect/{MethodAccessorImpl,ConstructorAccessorImpl,SerializationConstructorAccessorImpl}"
// [CONSTANT_Class_info] for above
// [UTF-8] [Target class's name]
// [CONSTANT_Class_info] for above
// ^ [UTF-8] [Serialization: Class's name in which to invoke constructor]
// ^ [CONSTANT_Class_info] for above
// [UTF-8] target method or constructor name
// [UTF-8] target method or constructor signature
// [CONSTANT_NameAndType_info] for above
// [CONSTANT_Methodref_info or CONSTANT_InterfaceMethodref_info] for target method
// [UTF-8] "invoke" or "newInstance"
// [UTF-8] invoke or newInstance descriptor
// [UTF-8] descriptor for type of non-primitive parameter 1
// [CONSTANT_Class_info] for type of non-primitive parameter 1
// ...
// [UTF-8] descriptor for type of non-primitive parameter n
// [CONSTANT_Class_info] for type of non-primitive parameter n
// + [UTF-8] "java/lang/Exception"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "java/lang/ClassCastException"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "java/lang/NullPointerException"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "java/lang/IllegalArgumentException"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "java/lang/InvocationTargetException"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "<init>"
// + [UTF-8] "()V"
// + [CONSTANT_NameAndType_info] for above
// + [CONSTANT_Methodref_info] for NullPointerException's constructor
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor
// + [UTF-8] "(Ljava/lang/String;)V"
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/String;)V"
// + [CONSTANT_Methodref_info] for IllegalArgumentException's constructor taking a String
// + [UTF-8] "(Ljava/lang/Throwable;)V"
// + [CONSTANT_NameAndType_info] for "<init>(Ljava/lang/Throwable;)V"
// + [CONSTANT_Methodref_info] for InvocationTargetException's constructor
// + [CONSTANT_Methodref_info] for "super()"
// + [UTF-8] "java/lang/Object"
// + [CONSTANT_Class_info] for above
// + [UTF-8] "toString"
// + [UTF-8] "()Ljava/lang/String;"
// + [CONSTANT_NameAndType_info] for "toString()Ljava/lang/String;"
// + [CONSTANT_Methodref_info] for Object's toString method
// + [UTF-8] "Code"
// + [UTF-8] "Exceptions"
// * [UTF-8] "java/lang/Boolean"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(Z)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "booleanValue"
// * [UTF-8] "()Z"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Byte"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(B)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "byteValue"
// * [UTF-8] "()B"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Character"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(C)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "charValue"
// * [UTF-8] "()C"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Double"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(D)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "doubleValue"
// * [UTF-8] "()D"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Float"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(F)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "floatValue"
// * [UTF-8] "()F"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Integer"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(I)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "intValue"
// * [UTF-8] "()I"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Long"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(J)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "longValue"
// * [UTF-8] "()J"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "java/lang/Short"
// * [CONSTANT_Class_info] for above
// * [UTF-8] "(S)V"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
// * [UTF-8] "shortValue"
// * [UTF-8] "()S"
// * [CONSTANT_NameAndType_info] for above
// * [CONSTANT_Methodref_info] for above
short numCPEntries = NUM_BASE_CPOOL_ENTRIES + NUM_COMMON_CPOOL_ENTRIES;
boolean usesPrimitives = usesPrimitiveTypes();
if (usesPrimitives) {
numCPEntries += NUM_BOXING_CPOOL_ENTRIES;
}
if (forSerialization) {
numCPEntries += NUM_SERIALIZATION_CPOOL_ENTRIES;
}
// Add in variable-length number of entries to be able to describe
// non-primitive parameter types and checked exceptions.
numCPEntries += (short)(2 * numNonPrimitiveParameterTypes());
(add(numCPEntries, S1));
final String generatedName = generateName(isConstructor, forSerialization);
asm.emitConstantPoolUTF8(generatedName);
(());
thisClass = ();
if (isConstructor) {
if (forSerialization) {
asm.emitConstantPoolUTF8("sun/reflect/SerializationConstructorAccessorImpl");
} else {
asm.emitConstantPoolUTF8("sun/reflect/ConstructorAccessorImpl");
}
} else {
asm.emitConstantPoolUTF8("sun/reflect/MethodAccessorImpl");
}
(());
superClass = ();
asm.emitConstantPoolUTF8(getClassName(declaringClass, false));
(());
targetClass = ();
short serializationTargetClassIdx = (short) 0;
if (forSerialization) {
asm.emitConstantPoolUTF8(getClassName(serializationTargetClass, false));
(());
serializationTargetClassIdx = ();
}
asm.emitConstantPoolUTF8(name);
asm.emitConstantPoolUTF8(buildInternalSignature());
(sub((), S1), ());
if (isInterface()) {
(targetClass, ());
} else {
if (forSerialization) {
(serializationTargetClassIdx, ());
} else {
(targetClass, ());
}
}
targetMethodRef = ();
if (isConstructor) {
asm.emitConstantPoolUTF8("newInstance");
} else {
asm.emitConstantPoolUTF8("invoke");
}
invokeIdx = ();
if (isConstructor) {
asm.emitConstantPoolUTF8("([Ljava/lang/Object;)Ljava/lang/Object;");
} else {
asm.emitConstantPoolUTF8("(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
}
invokeDescriptorIdx = ();
// Output class information for non-primitive parameter types
nonPrimitiveParametersBaseIdx = add((), S2);
for (int i = 0; i < ; i++) {
Class <? > c = parameterTypes[i];
if (!isPrimitive(c)) {
asm.emitConstantPoolUTF8(getClassName(c, false));
(());
}
}
// Entries common to FieldAccessor, MethodAccessor and ConstructorAccessor
emitCommonConstantPoolEntries();
// Boxing entries
if (usesPrimitives) {
emitBoxingContantPoolEntries();
}
if (() != numCPEntries) {
throw new InternalError("Adjust this code (cpi = " + () +
", numCPEntries = " + numCPEntries + ")");
}
// Access flags
(ACC_PUBLIC);
// This class
(thisClass);
// Superclass
(superClass);
// Interfaces count and interfaces
(S0);
// Fields count and fields
(S0);
// Methods count and methods
(NUM_METHODS);
emitConstructor();
emitInvoke();
// Additional attributes (none)
(S0);
// Load class
();
final byte[] bytes = ();
// Note: the class loader is the only thing that really matters
// here -- it's important to get the generated code into the
// same namespace as the target class. Since the generated code
// is privileged anyway, the protection domain probably doesn't
// matter.
return (
new PrivilegedAction < MagicAccessorImpl > () {
public MagicAccessorImpl run() {
try {
return (MagicAccessorImpl)
(generatedName,
bytes,
0,
,
()).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new InternalError(e);
}
}
});
}
Look mainly at this line: (xx, ()).newInstance();
In the method implementation, a DelegatingClassLoader class loader object is generated every time it is called , where a new class loader is generated every time for performance considerations, and these generated classes can be uninstalled in some cases, because the uninstallation of a class is only possible if the class loader can be reclaimed, and if the original class loader is used, that may result in these newly created classes never being unloaded.
The classes generated by reflection can sometimes be used and uninstalled, so using their own class loader makes it easier to control the life cycle of the reflected classes.
Reflection Call Flow Summary
- Reflection classes and reflection methods are obtained by searching through a list to find matching methods, so the lookup performance varies with the size of the class and the number of methods;
- Each class will have a Class instance that corresponds to it, so that each class can get the method reflection method and act on other instances;
- Reflection is also considered thread-safe, so feel free to use it;
- Reflection uses soft references to relectionData to cache class information, avoiding the overhead of re-fetching it from jvm each time;
- Reflection calls generate a new proxy Accessor multiple times, while bytecode survival takes uninstallation into account, so a separate class loader is used;
- When the required method is found, a copy of it is made instead of using the original instance, thus ensuring data isolation;
- Dispatch the reflection method, which is ultimately executed by jvm executing invoke0();
About the Author.
From the first-line programmer Seven's exploration and practice, continuous learning iteration in the~
This article is included in my personal blog:https://
Public number: seven97, welcome to follow~