您的位置:首页 > 编程语言 > Java开发

【盘点Java框架常用技术】Java反射

2019-08-15 21:32 218 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/HoyingHan/article/details/99656570

【一】简介

  • 允许运行时的Java程序获取自身信息,同时操作类或对象的内部属性,最通俗易懂的解释,就是让你根据一个String来得到你要的实体对象
  • 功能:
      运行时判断对象所属类
    1. 运行时构造类的对象
    2. 运行时判断类的属性和方法
    3. 运行时调用任意一个类的方法

下面是相关的四个类,包含了我们定义一个类所能用到的所有属性和方法。

  • Class
  • Field
  • Method
  • Constructor

【二】常用方法

  1. 获取Class对象

      Class类中的静态方法forName
    • 直接获取某一个对象的 class
    • 调用某个对象的 getClass() 方法
  2. 反射获取类的属性

      getFields():Field[] - 只能获取public的字段,包括父类的
    • **getDeclaredFields():Field[] **- 只能获取自己声明的各种字段,包括public,protected,private
  3. 获取方法:

      getMethod(String,Class<?>…):Method - 根据方法名和参数获取方法
    • getDeclaredMethods():Method[]
  4. invoke()

    调用包装在当前Method对象中的方法

    Method和NativeMethodAccessorImpl类中的invoke()方法:

    public Object invoke(Object obj, Object... args)
    throws IllegalAccessException, IllegalArgumentException,
    InvocationTargetException
    {
    if (!override) {
    if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
    Class<?> caller = Reflection.getCallerClass();
    checkAccess(caller, clazz, obj, modifiers);
    }
    }
    MethodAccessor ma = methodAccessor;
    if (ma == null) {
    ma = acquireMethodAccessor();
    }
    return ma.invoke(obj, args);
    }
    public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
    if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
    MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
    this.parent.setDelegate(var3);
    }
    return invoke0(this.method, var1, var2);
    }

在上述方法中,有两点是比较重要的:

  1. 根据Class对象获取Method方法时,参数:方法名和参数的CLass类型
  2. 调用method.invoke(obj, args)

【三】原理探究

如果想要理解反射,就首先要对Java类加载的方式有了解。

我们知道,我们写的Java文件会被编译成.class文件(字节码文件),才能在JVM中执行,是通过类加载器进行加载,

java.lang.ClassLoader#loadClass(java.lang.String, boolean)
是加载一个类的核心方法,

protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
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) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}

if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);

// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}

主要逻辑分为3步

  1. 检查是否已加载,如果已加载则直接返回
  2. 遵循双亲委派模式,先调用父类加载器加载器
  3. 如果父类加载器加载失败,调用findClass加载

当我们打开findClass方法时,会不会有些诧异,直接抛了个异常,这是因为ClassLoader是一个抽象类,是无法通过new创建一个对象的,也就是说,你无法通过ClassLoader类直接加载.class文件,只能写一个子类继承ClassLoader,然后覆盖findClass方法,定义自己的加载逻辑。

protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}

在自定义加载逻辑的时候,通常的做法是,读取一个字节数组byte[] b,然后调用ClassLoader的defineClass()方法,于是返回了一个Class对象

private native Class<?> defineClass0(String name, byte[] b, int off, int len,
ProtectionDomain pd);

private native Class<?> defineClass1(String name, byte[] b, int off, int len,
ProtectionDomain pd, String source);

private native Class<?> defineClass2(String name, java.nio.ByteBuffer b,
int off, int len, ProtectionDomain pd,
String source);

Class类的内部类 ReflectionData,里面的内容与xxx.class文件中的内容映射,作用就是缓存从JVM中读取类的如下属性数据。同时由于一个类中包含的内容信息量过大,所以被拆成了四个类,也就是上面提到的- Class、Field、Method、Constructor

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) {
this.redefinedCount = redefinedCount;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: