Java反射性能——替代方案

2024-04-24

各种问题中讨论的主题(参考文献1 https://stackoverflow.com/questions/19557829/faster-alternatives-to-javas-reflection/19563000#19563000, 参考资料2 https://stackoverflow.com/questions/49945423/why-does-java-lamda-reflection-performance-get-worse)。但为什么我发现 lambda 反射的性能要差得多?人们常常声称 lambda 反射与直接访问一样快。但下面的测试显示了其他结果。这里场反射似乎几乎与 lambda 反射一样快。

重复测试:源代码如下。

测试输出:

run:
> Test: Main (Class=Person1, name=Age)
> RUN 0
Loops: 50000000
Warmup
createLambda: new getter for clazz=lambda.Person1 name=Age
createLambda: new setter for clazz=lambda.Person1 name=Age
Run
GET FIELD=0.17s METHOD=0.66s DIRECT=0.03s LAMBDA=0.18s
SET FIELD=0.29s METHOD=0.68s DIRECT=0.03s LAMBDA=0.15s
> RUN 1
Loops: 50000000
Warmup
Run
GET FIELD=0.19s METHOD=0.41s DIRECT=0.02s LAMBDA=0.14s
SET FIELD=0.22s METHOD=0.64s DIRECT=0.04s LAMBDA=0.14s
> Test: Main (Class=Person2, name=Age)
> RUN 0
Loops: 50000000
Warmup
createLambda: new getter for clazz=lambda.Person2 name=Age
createLambda: new setter for clazz=lambda.Person2 name=Age
Run
GET FIELD=0.17s METHOD=0.42s DIRECT=0.02s LAMBDA=0.17s
SET FIELD=0.23s METHOD=0.65s DIRECT=0.04s LAMBDA=0.18s
> RUN 1
Loops: 50000000
Warmup
Run
GET FIELD=0.17s METHOD=0.42s DIRECT=0.02s LAMBDA=0.16s
SET FIELD=0.23s METHOD=0.68s DIRECT=0.05s LAMBDA=0.19s
> Test: Main (Class=Person3, name=Age)
> RUN 0
Loops: 50000000
Warmup
createLambda: new getter for clazz=lambda.Person3 name=Age
createLambda: new setter for clazz=lambda.Person3 name=Age
Run
GET FIELD=0.15s METHOD=0.39s DIRECT=0.02s LAMBDA=0.28s
SET FIELD=0.23s METHOD=0.62s DIRECT=0.03s LAMBDA=0.29s
> RUN 1
Loops: 50000000
Warmup
Run
GET FIELD=0.16s METHOD=0.40s DIRECT=0.02s LAMBDA=0.28s
SET FIELD=0.23s METHOD=0.62s DIRECT=0.04s LAMBDA=0.29s
> Test: Main (Class=Person1, name=Age)
> RUN 0
Loops: 50000000
Warmup
Run
GET FIELD=0.17s METHOD=0.41s DIRECT=0.02s LAMBDA=0.32s
SET FIELD=0.24s METHOD=0.62s DIRECT=0.04s LAMBDA=0.31s
> RUN 1
Loops: 50000000
Warmup
Run
GET FIELD=0.16s METHOD=0.42s DIRECT=0.02s LAMBDA=0.24s
SET FIELD=0.23s METHOD=0.59s DIRECT=0.03s LAMBDA=0.24s
BUILD SUCCESSFUL (total time: 32 seconds)

使用 JMH(代码见下文),单个 fork 运行基准测试的结果为:

Benchmark        Mode  Cnt  Score   Error  Units
Test.doGetTest1  avgt    5  6,133 ± 0,578  ns/op    (FIELD)
Test.doGetTest2  avgt    5  7,947 ± 0,970  ns/op    (METHOD)
Test.doGetTest3  avgt    5  2,294 ± 0,140  ns/op    (DIRECT)
Test.doGetTest4  avgt    5  3,802 ± 0,479  ns/op    (LAMBDA)
Test.doGetTest5  avgt    5  5,347 ± 0,530  ns/op    (METHODHANDLE)

Test.doSetTest1  avgt    5  8,727 ± 0,918  ns/op    (FIELD)
Test.doSetTest2  avgt    5  7,760 ± 0,382  ns/op    (METHOD)
Test.doSetTest3  avgt    5  2,448 ± 0,255  ns/op    (DIRECT)
Test.doSetTest4  avgt    5  4,230 ± 0,160  ns/op    (LAMBDA)
Test.doSetTest5  avgt    5  5,729 ± 0,576  ns/op    (METHODHANDLE)

Where

# JMH version: 1.21
# VM version: JDK 1.8.0_172, Java HotSpot(TM) 64-Bit Server VM, 25.172-b11
# VM invoker: C:\Program Files\Java\jre1.8.0_172\bin\java.exe
# VM options: <none>

package lambda;

public class Main {

    public static void main(String[] args) throws Exception {

        int runs = 2;

        lambda.Test.doTestRuns("Main", runs, Person1.class, "Age", new Person1());
        lambda.Test.doTestRuns("Main", runs, Person2.class, "Age", new Person2());
        lambda.Test.doTestRuns("Main", runs, Person3.class, "Age", new Person3());
        lambda.Test.doTestRuns("Main", runs, Person1.class, "Age", new Person1());
    }

}

package lambda;

public class Person1 {

    public long Age = 0;

    public long getAge() {
        return Age;
    }

    public void setAge(long age) {
        this.Age = age;
    }
}

package lambda;

public class Person2 {

    public long Age = 0;

    public long getAge() {
        return Age;
    }

    public void setAge(long age) {
        this.Age = age;
    }
}

package lambda;

public class Person3 {

    public long Age = 0;

    public long getAge() {
        return Age;
    }

    public void setAge(long age) {
        this.Age = age;
    }
}

package lambda;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import lambda.LambdaFactory.Lambda;

public class Test {
    long loops = 50_000_000;

    static LambdaFactory lamFactory = new LambdaFactory();

    public static void doTestRuns(String label, int runs, Class clazz, String name, Object o) throws Exception {
        System.out.println("> Test: " + label + " (Class=" + clazz.getSimpleName() + ", name=" + name + ")");

        Test test = new Test();     
        for (int i = 0; i < runs; i++) {
            System.out.println("> RUN " + i);
            test.doTest(clazz, name, o);
        }
    }

    public void doTest(Class clazz, String name, Object o) throws NoSuchFieldException, IllegalArgumentException, Exception {
        final long[] dummy=new long[8];

        System.out.println("Loops: " + loops);

        // needed for Direct method tests
        Person1 p = new Person1();

        System.out.println("Warmup");
        dummy[0] += doGetTest1(dummy[0], clazz, name, o);
        dummy[1] += doGetTest2(dummy[1], clazz, name, o);
        dummy[2] += doGetTest3(dummy[2], p);
        dummy[3] += doGetTest4(dummy[3], clazz, name, o);
        dummy[4] += doSetTest1(dummy[4], clazz, name, o);
        dummy[5] += doSetTest2(dummy[5], clazz, name, o);
        dummy[6] += doSetTest3(dummy[6], p);
        dummy[7] += doSetTest4(dummy[7], clazz, name, o);

        System.out.println("Run");      
        long t0 = System.nanoTime();
        dummy[0] += doGetTest1(dummy[0], clazz, name, o);
        long t1 = System.nanoTime();
        dummy[1] += doGetTest2(dummy[1], clazz, name, o);
        long t2 = System.nanoTime();
        dummy[2] += doGetTest3(dummy[2], p);
        long t3 = System.nanoTime();
        dummy[3] += doGetTest4(dummy[3], clazz, name, o);
        long t4 = System.nanoTime();
        dummy[4] += doSetTest1(dummy[4], clazz, name, o);
        long t5 = System.nanoTime();
        dummy[5] += doSetTest2(dummy[5], clazz, name, o);
        long t6 = System.nanoTime();
        dummy[6] += doSetTest3(dummy[6], p);
        long t7 = System.nanoTime();
        dummy[7] += doSetTest4(dummy[7], clazz, name, o);
        long t8 = System.nanoTime();

        System.out.printf("GET FIELD=%.2fs METHOD=%.2fs DIRECT=%.2fs LAMBDA=%.2fs\n",
                ((t1 - t0) / 1000000000.0),
                ((t2 - t1) / 1000000000.0),
                ((t3 - t2) / 1000000000.0),
                ((t4 - t3) / 1000000000.0));

        System.out.printf("SET FIELD=%.2fs METHOD=%.2fs DIRECT=%.2fs LAMBDA=%.2fs\n",
                ((t5 - t4) / 1000000000.0),
                ((t6 - t5) / 1000000000.0),
                ((t7 - t6) / 1000000000.0),
                ((t8 - t7) / 1000000000.0));
    }

    public long doGetTest1(long v, Class clazz, String name, Object o) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        Field field = clazz.getField(name);
        for (int i = 0; i < loops; i++) {
            v += (long)field.get(o);
        }
        return v;
    }

    public long doGetTest2(long v, Class clazz, String name, Object o) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Method method = clazz.getMethod("get" + name);
        for (int i = 0; i < loops; i++) {
            v += (long)method.invoke(o);
        }
        return v;
    }

    public long doGetTest3(long v, Person1 p) {
        for (int i = 0; i < loops; i++) {
            v += (long) p.getAge();
        }
        return v;
    }

    public Long doGetTest4(long v, Class clazz, String name, Object o) throws Exception {
        Lambda lam = lamFactory.createLambda(clazz, name);
        for (int i = 0; i < loops; i++) {
            v += (long) lam.get(o);
        }
        return v;
    }

    public long doSetTest1(long v, Class clazz, String name, Object o) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        long value = 1;
        Field field = clazz.getField(name);
        for (int i = 0; i < loops; i++) {
            field.set(o, value);
            value++;
        }
        return v + value;
    }

    public long doSetTest2(long v, Class clazz, String name, Object o) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        long value = 1;
        Method getter = clazz.getMethod("get" + name);
        Method method = clazz.getMethod("set" + name, getter.getReturnType());
        for (int i = 0; i < loops; i++) {
            method.invoke(o, value);
            value++;
        }
        return v + value;
    }

    public long doSetTest3(long v, Person1 p) {
        long value = 1;
        for (int i = 0; i < loops; i++) {
            p.setAge(value);
            value++;
        }
        return v + value;
    }

    public long doSetTest4(long v, Class clazz, String name, Object o) throws Exception {
        Lambda lam = lamFactory.createLambda(clazz, name);
        long value = 1;
        for (int i = 0; i < loops; i++) {
            lam.set(o, value);
            value++;
        }
        return v + value;
    }

}

package lambda;

import java.lang.invoke.CallSite;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.function.BiConsumer;
import java.util.function.Function;

public class LambdaFactory {

    // create a cache of Functions and BiConsumers
    public HashMap<Method, Function> getters = new HashMap();
    public HashMap<Method, BiConsumer> setters = new HashMap();

    // get the lookup factory once
    MethodHandles.Lookup lookup = MethodHandles.lookup();

    public Lambda createLambda(Class clazz, String name) throws Exception {

        Method getterMethod = clazz.getMethod("get" + name);
        Function getterFunction = getters.get(getterMethod);
        if (getterFunction == null) {
            MethodHandle mh = lookup.unreflect(getterMethod);
            getterFunction = createGetter(lookup, mh);
            getters.put(getterMethod, getterFunction);
            System.out.println("createLambda: new getter for clazz=" + clazz.getName() + " name=" + name);
        }

        Method setterMethod = clazz.getMethod("set" + name, getterMethod.getReturnType());
        BiConsumer setterFunction = setters.get(setterMethod);
        if (setterFunction == null) {
            MethodHandle mh = lookup.unreflect(setterMethod);
            setterFunction = createSetter(lookup, mh);
            setters.put(setterMethod, setterFunction);
            System.out.println("createLambda: new setter for clazz=" + clazz.getName() + " name=" + name);
        }

        return new Lambda(getterFunction, setterFunction);
    }

    private Function createGetter(final MethodHandles.Lookup lookup,
            final MethodHandle getter) throws Exception {
        final CallSite site = LambdaMetafactory.metafactory(lookup, "apply",
                MethodType.methodType(Function.class),
                MethodType.methodType(Object.class, Object.class), //signature of method Function.apply after type erasure
                getter,
                getter.type()); //actual signature of getter
        try {
            return (Function) site.getTarget().invokeExact();
        } catch (final Exception e) {
            throw e;
        } catch (final Throwable e) {
            throw new Exception(e);
        }
    }

    private BiConsumer createSetter(final MethodHandles.Lookup lookup,
            final MethodHandle setter) throws Exception {
        final CallSite site = LambdaMetafactory.metafactory(lookup,
                "accept",
                MethodType.methodType(BiConsumer.class),
                MethodType.methodType(void.class, Object.class, Object.class), //signature of method BiConsumer.accept after type erasure
                setter,
                setter.type()); //actual signature of setter
        try {
            return (BiConsumer) site.getTarget().invokeExact();
        } catch (final Exception e) {
            throw e;
        } catch (final Throwable e) {
            throw new Exception(e);
        }
    }

    public class Lambda {

        private final Function getterFunction;
        private final BiConsumer setterFunction;

        public Lambda(Function getterFunction, BiConsumer setterFunction) {
            this.getterFunction = getterFunction;
            this.setterFunction = setterFunction;
        }

        public Object get(Object theObject) {
            return getterFunction.apply(theObject);
        }

        public void set(Object theObject, Object value) {
            setterFunction.accept(theObject, value);
        }
    }
}

JMH代码:

package lambda;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lambda.LambdaFactory.Lambda;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;

public class Test {

    @State(Scope.Thread)
    public static class MyState {
        LambdaFactory lamFactory;
        Lambda lam;

        Field field;
        Method getterMethod;
        Method setterMethod;

        MethodHandle getterHandle;
        MethodHandle setterHandle;

        Person1 object;
        long value;

        @Setup(Level.Trial)
        public void doSetup() throws Exception {

            lamFactory = new LambdaFactory();
            lam = lamFactory.createLambda(Person1.class, "Age");

            field = Person1.class.getField("Age");
            getterMethod = Person1.class.getMethod("getAge");
            setterMethod = Person1.class.getMethod("setAge", long.class);

            MethodHandles.Lookup lookup = MethodHandles.lookup();
            getterHandle = lookup.unreflect(getterMethod);
            setterHandle = lookup.unreflect(setterMethod);

            object = new Person1();
            value = 123;
            System.out.println("Do Setup");
        }

        @TearDown(Level.Trial)
        public void doTearDown() {
            System.out.println("Do TearDown");
        }
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doGetTest1(MyState state) throws IllegalArgumentException, IllegalAccessException {
        long v = (long) state.field.get(state.object);
        return v;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doGetTest2(MyState state) throws IllegalAccessException, InvocationTargetException {
        long v = (long) state.getterMethod.invoke(state.object);
        return v;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doGetTest3(MyState state) throws IllegalAccessException, InvocationTargetException {
        long v = state.object.getAge();
        return v;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doGetTest4(MyState state) throws IllegalAccessException, InvocationTargetException {
        long v = (long) state.lam.get(state.object);
        return v;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doGetTest5(MyState state) throws IllegalAccessException, InvocationTargetException, Throwable {
        long v = (long) state.getterHandle.invoke(state.object);
        return v;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doSetTest1(MyState state) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        state.field.set(state.object, state.value);
        return state.value;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doSetTest2(MyState state) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        state.setterMethod.invoke(state.object, state.value);
        return state.value;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doSetTest3(MyState state) {
        state.object.setAge(state.value);
        return state.value;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doSetTest4(MyState state) throws Exception {
        state.lam.set(state.object, state.value);
        return state.value;
    }

    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.NANOSECONDS)
    public long doSetTest5(MyState state) throws Exception, Throwable {
        state.setterHandle.invoke(state.object, state.value);
        return state.value;
    }

}

None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java反射性能——替代方案 的相关文章

随机推荐

  • 在仪表板标题中间对齐可变长度的文本

    我使用闪亮的仪表板包 标题需要有标题 文本和徽标 标题应位于左侧 文本应位于标题的中间 中心 徽标应位于右侧 仪表板侧边栏还有两个过滤器 选择输入 中间的文本显示用户选择 因此文本的长度根据不同的选择而不同 我没有 css 背景 也不知道如
  • 如何将参数传递给 DLL 初始化(例如,通过 LoadLibrary 加载时)?

    如何将参数传递给通过 LoadLibrary 加载的 DLL 的初始化函数 有可能吗 也就是说 无需求助于某种导出函数或共享内存 没有直接的方法 最简单的可能是通过环境变量 它们可以在调用之前轻松设置LoadLibray with sete
  • NgRx - 状态如何组合和初始化

    当我们初始化 Store 时 StoreModule provideStore r1 Reducer1 r2 Reducer2 我们确实将减速器传递到 Store 进行存储 但我们实际上从未将初始状态传递给存储 除了在减速器函数中定义它 c
  • 有没有办法覆盖动作脚本运算符,特别是我想覆盖等于运算符

    是否可以覆盖 equals 运算符 即 对于可以通过 2 个或更多字段匹配来确定相等性的客户类别 如果您的意思是重载 作为 equals 的同义词 那么您不能 因为 ActionScript 不提供运算符重载 只需为您的类编写一个 equa
  • 收到 SIGNAL 11 错误

    再会 我有一个关于使用 SDK 开发 Android 应用程序的问题 我们的应用程序在 Android 2 1 API Level 7 下遇到问题 至少在 Android 2 1 update1 模拟器和 Motorola Droid X
  • 在 post-command-hook 中,这个用于kill-word的命令已经以某种方式变成了kill-region

    In my post command hook回调 当我这样做时kill word the this command var is kill region 并不是kill word正如预期的那样 我想那是因为kill word uses k
  • Swift 3.0 将图像写入目录

    我有一个简单的ImagePicker供用户选择或拍摄个人资料照片 我想保存这个image to the Home Directory方便以后加载 问题是未设置图像类型 Save Image PPimagePicked image let i
  • Spark 2.0 弃用了“DirectParquetOutputCommitter”,没有它如何生活?

    最近 我们从 HDFS 上的 EMR gt S3 上的 EMR 启用了一致视图的 EMRFS 迁移 我们意识到 Spark SaveAsTable 镶木地板格式 写入 S3 的速度比 HDFS 慢约 4 倍 但我们发现使用 DirectPa
  • 在 MySQL 中的分组列中搜索?

    我需要创建一个男人的数据库 男人可以有一个或多个属性 每个男人的属性都有一个特定的值 听起来很简单吧 好吧 继续阅读 因为这个问题有点不可能 5 天处理它 s 所以我创建了这 3 个表 CREATE TABLE guy id int 11
  • Int32 和 UInt32 有什么区别?

    有什么区别Int32 and UInt32 如果它们与容量范围能力相同 问题是出于什么原因UInt32被创造了 我应该什么时候使用UInt32代替Int32 UInt32 不允许负数 从MSDN http msdn microsoft co
  • 修复了滚动 html 文档时的 div

    我正在寻找一个 jquery 插件 可以让我实现这种效果 静态向下滚动 http www bnet com blog drug business it 8217s a trap congress wants to see j j ceo s
  • jQuery hide() div 直到完全加载

    我正在为我的博客使用选项卡式特色帖子 如何实施div latest featured will hide then show 内容完全加载后它会回来吗 document ready function Default Action tab c
  • 从 pod 连接到其他 pod

    基本上 我有一个部署 它创建了 3 个自动扩展的容器 PHP FPM NGINX 和包含应用程序的容器 所有这些都设置了机密 服务和入口 该应用程序还在 PHP FPM 和 NGINX 之间共享项目 因此一切都已设置完毕 由于我想使用 K8
  • M1 Apple Silicon Mac 上的 Dynamodb 本地设置

    我使用 dynamodb 进行了本地设置https docs aws amazon com amazondynamodb latest developerguide DynamoDBLocal DownloadingAndRunning h
  • iOS - iOS 设备和外部配件 (BluetoothWatch) 之间 BLE 数据传输的 MTU 大小

    我正在为使用 BLE CoreBluetooth 的蓝牙手表开发 iOS 应用程序 Objective C 并且我的手表具有 GATT 蓝牙配置文件 iOS 应用程序最低支持来自 iOS7 我想知道如何使用 Core Bluetooth 框
  • 如何从 SDK 插件数据文件夹加载 dll?

    我们使用 Web IDE 来创建插件 我的 test dll 位于数据文件夹中 如何通过js ctypes加载它 使用像 c test dll 这样的绝对路径没有问题 但我无法使用此路径来分发它 var lib ctypes open c
  • Linux 中的机器人框架

    如何借助Robot框架获取Linux中执行的命令的状态 例如如果使用这个 SSHLibrary open Connection server SSHLibrary login xxxxx xxxxx 1111 Write command 2
  • 最近有关于 JVM 的书吗? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 如何重命名 iOS 8 Today Widget?

    我刚刚开始尝试将 iOS 8 Today Widget 添加到我的应用程序中 到目前为止一切顺利 但我遵循原始模板并使用 TodayWidget 作为名称创建了我的小部件 在 Xcode 中我的应用程序文件的上下文中 目标 产品名称很好 但
  • Java反射性能——替代方案

    各种问题中讨论的主题 参考文献1 https stackoverflow com questions 19557829 faster alternatives to javas reflection 19563000 19563000 参考