"反射比直接调用慢"几乎是常识,但慢多少、setAccessible(true) 到底有没有用、用了能省多少,很少有人给出具体数字。真实计时三种调用方式,各跑 5000 万次。
上一篇:两个一模一样的类:真实用两个 ClassLoader 造出两个不能互相强转的 Foo
一个最简单的静态方法,分别用直接调用、Method.invoke()(未 setAccessible)、Method.invoke()(已 setAccessible)三种方式各调 5000 万次。
ReflectionCost.java(三种调用方式) static int add(int a, int b) { return a + b; } Method m = ReflectionCost.class.getDeclaredMethod("add", int.class, int.class); Method mAccessible = ReflectionCost.class.getDeclaredMethod("add", int.class, int.class); mAccessible.setAccessible(true); // 直接调用 sum1 += add(i, 1); // 反射调用(未 setAccessible) sum2 += (int) m.invoke(null, i, 1); // 反射调用(已 setAccessible) sum3 += (int) mAccessible.invoke(null, i, 1);
三组循环共享同一段预热(先各跑 200 万次让 JIT 充分热身),正式计时前用求和结果做一致性校验,排除任何一组算错的可能。
两次独立运行,结果量级完全一致。
循环 50000000 次(结果校验: sum1==sum2==sum3 -> true): 直接调用 耗时 = 32ms 反射调用(未 setAccessible) 耗时 = 208ms 反射调用(已 setAccessible) 耗时 = 96ms 反射/直接 倍数 = 6.5 setAccessible 前后倍数 = 2.15
直接调用 耗时 = 32ms 反射调用(未 setAccessible) 耗时 = 201ms 反射调用(已 setAccessible) 耗时 = 105ms 反射/直接 倍数 = 6.2 setAccessible 前后倍数 = 1.90
真实数据非常稳定:反射调用相对直接调用慢 6.2~6.5 倍;调用 setAccessible(true) 之后,反射调用耗时降到原来的一半左右(倍数 1.9~2.15),但依然比直接调用慢约 3 倍。三组结果全程 sum1==sum2==sum3 校验通过,差距纯粹来自调用方式本身,不是计算逻辑不一致。
每一行都是真实运行这段代码得到的结果。