java反射使用和源码解析

1         反射

1.1            什么是反射

正射:指的是我们知道类的定义和类中的方法名称,直接先创建对象,然后通过对象去调用方法。例如:

Apple apple = new Apple(); //直接初始化,「正射」

apple.setPrice(4);

反射:指的是一开始不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象,需要用JDK 提供的反射 API 进行反射调用。需要通过类的路径字符串创建对象,通过方法名称字符串调用方法。例如:

Class clz = Class.forName("com.chenshuyi.reflect.Apple");//通过字符串获取类Class

Constructor constructor = clz.getConstructor();//获取类的构造器

Object object = constructor.newInstance();//创建对象

Method method = clz.getMethod("setPrice", int.class);//通过方法名获取方法

method.invoke(object, 4);//调用方法;

第一段代码在未运行时就已经确定了要运行的类(Apple),而第二段代码则是在运行时通过字符串值才得知要运行的类(com.chenshuyi.reflect.Apple)。反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

1.2            反射获取类、构造器、方法、属性

(1)获取类

使用 Class.forName 静态方法。当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象。

Class clz = Class.forName("java.lang.String");

(2)获取构造器

通过 Constructor 对象的 newInstance() 方法

Constructor constructor = clz.getConstructor();//获取类的构造器

Object object = constructor.newInstance();//创建对象

(1)   获取方法

获取方法的 Method 对象

Method setPriceMethod = clz.getMethod("setPrice", int.class);

利用 invoke 方法调用方法

setPriceMethod.invoke(appleObj, 14);

(2)   获取属性

过 Class 对象的 getFields() 方法可以获取 Class 类的属性,但无法获取私有属性。

Class clz = Apple.class;

Field[] fields = clz.getFields();

for (Field field : fields) {

    System.out.println(field.getName());

}

输出结果是:

Price

(5)获取包含私有属性

而如果使用 Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性:

Class clz = Apple.class;

Field[] fields = clz.getDeclaredFields();

for (Field field : fields) {

    System.out.println(field.getName());

}

输出结果是:

name

price

1.3           反射的源码解析

(1)Method的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;             // read volatile

        if (ma == null) {

            ma = acquireMethodAccessor();

        }

        return ma.invoke(obj, args);

}

(2)acquireMethodAccessor 返回MethodAccessor对象

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 = root.getMethodAccessor();

        if (tmp != null) {

            methodAccessor = tmp;

        } else {

            // Otherwise fabricate one and propagate it up to the root

            tmp = reflectionFactory.newMethodAccessor(this);

            setMethodAccessor(tmp);

        }

        return tmp;

    }

(3)反射工厂返回对象reflectionFactory.newMethodAccessor

public MethodAccessor newMethodAccessor(Method var1) {
    checkInitted();
    if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) {
        return (new MethodAccessorGenerator()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers());
    } else {
        NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl(var1);
        DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
        var2.setParent(var3);
        return var3;// 最终返回的是DelegatingMethodAccessorImpl对象
    }
}

其中DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl(var2);
是将NativeMethodAccessorImpl var2对象作为入参,传入DelegatingMethodAccessorImpl的构造函数。那么构造函数内部做了什么?很关键!

DelegatingMethodAccessorImpl(MethodAccessorImpl var1) {

        this.setDelegate(var1);对象设置在Delegate属性中,后面会用到

}

delegate 属性的定义是private MethodAccessorImpl delegate;

(4)步骤(3)最终返回的是DelegatingMethodAccessorImpl对象,所以步骤(1)中return ma.invoke(obj, args);函数invoke是DelegatingMethodAccessorImpl的方法。看看DelegatingMethodAccessorImpl的invoke方法定义如下:

public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {

        return this.delegate.invoke(var1, var2);//调用了属性delegateinvoke方法;也就是NativeMethodAccessorImpl对象的invoke方法;    }

(5)NativeMethodAccessorImpl对象的invoke实现

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);

    }

每次NativeMethodAccessorImpl.invoke()方法被调用时,都会增加一个调用次数计数器numInvocations,看超过阈值 没有;一旦超过,则调用MethodAccessorGenerator.generateMethod()来生成Java版的 MethodAccessor的实现类,并且通过this.parent.setDelegate(var3);改变DelegatingMethodAccessorImpl所引用的MethodAccessor为 Java版。后续经由DelegatingMethodAccessorImpl.invoke()调用到的就是Java版的实现了。

注意到关键的invoke0()方法是个native方法。它在HotSpot VM里是由JVM_InvokeMethod()函数所支持的,不能在深入了:

JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0

(JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args)

{

    return JVM_InvokeMethod(env, m, obj, args);

}

为什么要这样先用native后又切换为java的呢?

就像注释里说的,实际的 MethodAccessor 实现有两个版本,一个是 Native 版本NativeMethodAccessorImpl,一个是 Java 版本MethodAccessorImpl。Java版本在第一次启动时,需要加载字节码实现Method.invoke() 和 Constructor.newInstance() ,比较耗时。所以Native 版本第一次启动比java版本快3-4倍,但是后面的调用java版本比Native快20倍。所以为了避免启动慢,第一次使用native版本快速启动。为了避免后续运行慢,在切换到java版本MethodAccessorImpl 对象去实现反射。

自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

https://www.cnblogs.com/bclshuai/p/11380657.html

百度云盘下载地址:

链接:https://pan.baidu.com/s/1swkQzCIKI3g3ObcebgpIDg

提取码:mc8l

微信公众号获取最新的软件和视频介绍

QStockView

原文地址:https://www.cnblogs.com/bclshuai/p/10617640.html