Java 反射机制的学习-02
程序员文章站
2022-10-03 16:11:30
上接: Java 反射机制的学习-01Java反射机制的原理探究将对 forName、newInstance、getDeclaredField/getDeckaredMethod、setAccessible、set/get、invoke 等方法进行探究探究代码://com.duo1j.reflect02.Mainpublic class Main { public static void main(String[] args) { try { Cla...
上接: Java 反射机制的学习-01
Java反射机制的原理探究
将对 forName、newInstance、getDeclaredField/getDeclaredMethod、setAccessible、set/get、invoke 等方法进行探究
探究代码:
//com.duo1j.reflect02.Main
public class Main {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("com.duo1j.reflect02.Test1");
Object instance = clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(instance, "jack");
Method method = clazz.getDeclaredMethod("hello");
method.invoke(instance);
} catch (Exception | Error e) {
e.printStackTrace();
}
}
}
//----------------------------------------------------------------
//com.duo1j.reflect02.Test1
public class Test1 {
private String name;
public void hello() {
System.out.println("Hello from " + name);
}
}
//--------------------------------------------------------------
//Console
Hello from jack
一、Class.forName(String className)
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
通过forName获取类信息主要调用forName0这个native方法交给jvm去处理
而 getClass() 直接调用了native方法
@CallerSensitive 注解表示该方法会根据调用者权限产生不同的处理
getCallerClass() 方法会返回调用者
获取类加载器后交给 native forName0 方法处理
//getCallerClass()
public class Main {
public void test() {
System.out.println(Reflection.getCallerClass(0));
System.out.println(Reflection.getCallerClass(1));
System.out.println(Reflection.getCallerClass(2));
System.out.println(Reflection.getCallerClass(3));
}
public static void main(String[] args) {
new Main().test();
}
}
//Console
class sun.reflect.Reflection
class com.duo1j.reflect02.Main
class com.duo1j.reflect02.Main
null
之后jvm会调用ClassLoader类进行类加载
- 检查是否加载,已加载则直接返回
- 双亲委派加载,加载到后直接返回
- 仍未加载, 则自行加载后返回
//java.lang.ClassLoader#loadClass(java.lang.String, boolean)
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先,检查类是否已经被加载
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
//双亲委派机制加载类
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//未找到该name的class异常
}
if (c == null) {
//若双亲委派未找到,则自己处理
long t1 = System.nanoTime();
c = findClass(name);
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
二、newInstance()
- 权限检测
- 查找构造器,并缓存cachedConstructor
- 调用构造器,返回实例
//java.lang.Class#newInstance
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException
{
//进行权限检测
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
//查找构造方法
//cachedConstructor 构造器缓存
if (cachedConstructor == null) {
//限制Class类的newInstance方法
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
//获取构造器
//getConstructor0会先获取所有构造器,然后根据参数匹配
//匹配成功后,通过copyConstructor返回一份拷贝
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// 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)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
//构造器调用,返回实例
Constructor<T> tmpConstructor = cachedConstructor;
//权限检查
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
三、getDeclaredField/getDeclaredMethod
这两者类似, 就选 getDeckaredMethod 来说一下
- 权限检测
- 通过privateGetDeclaredMethods获取方法列表
- searchMethods根据parameterTypes查找方法
@CallerSensitive
//java.lang.Class#getDeclaredMethod
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
{
//权限检测
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
//privateGetDeclaredMethods获取方法列表
//searchMethods根据parameterTypes查找对应方法
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
return method;
}
//java.lang.Class#privateGetDeclaredMethods
private Method[] privateGetDeclaredMethods(boolean publicOnly) {
checkInitted();
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods;
//存在缓存,从缓存中返回
if (res != null) return res;
}
//没有缓存,去虚拟机中获取
res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly));
if (rd != null) {
if (publicOnly) {
rd.declaredPublicMethods = res;
} else {
rd.declaredMethods = res;
}
}
return res;
}
四、setAccessible(boolean flag)
//java.lang.reflect.AccessibleObject#setAccessible(boolean)
public void setAccessible(boolean flag) throws SecurityException {
//权限检测
SecurityManager sm = System.getSecurityManager();
if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
//设置flag
setAccessible0(this, flag);
}
private static void setAccessible0(AccessibleObject obj, boolean flag)
throws SecurityException
{
//禁止设置Class类
if (obj instanceof Constructor && flag == true) {
Constructor<?> c = (Constructor<?>)obj;
if (c.getDeclaringClass() == Class.class) {
throw new SecurityException("Cannot make a java.lang.Class" +
" constructor accessible");
}
}
//private boolean override
obj.override = flag;
}
五、set/get()
set与get相似
//java.lang.reflect.Field#set
@CallerSensitive
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
//private boolean override同上
if (!override) {
//检查可访问性
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
//获取访问器 (FieldAccessor接口)
getFieldAccessor(obj).set(obj, value);
}
六、invoke(Object obj, Object… args)
- 访问性检查
- 拿到methodAccessor (MethodAccessor接口声明invoke)
- 如果第一次调用没有methodAccessor,则由acquireMethodAccessor创建
- 调用invoke
//java.lang.reflect.Method#invoke
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
//private boolean override同上
//访问性检查
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
//获取methodAccessor (MethodAccessor 接口)
MethodAccessor ma = methodAccessor; // read volatile
//第一次调用没有methodAccessor, 则由acquireMethodAccessor创建
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
总结:
- 反射涉及很多native方法调用,反射获得的class信息存入relectionData作缓存,避免反复从jvm中读取。
- 反射是线程安全的。
- 反射获取方法、字段等都是进行匹配,因而类的大小会影响反射获取的效率。
- 查找到的方法、构造器、字段等会使用copyConstructor/copyMethod/copyField返回拷贝,保证数据隔离。
如有错误,恳请指正
本文地址:https://blog.csdn.net/weixin_44506615/article/details/107578196