java反射效率到底如何,花了点时间,做了一个简单的测试.供大家参考.
测试背景:
1. 测试简单Bean(int,Integer,String)的set方法
2. loop 1亿次
3. 测试代码尽可能避免对象的创建,复发方法的调用,仅仅测试set方法的耗时
测试结果:
场景 |
本机测试结果(XP,双核,2G) |
服务器测试结果(Linux,XEN虚拟机,8核,5.5G)
|
方法直接调用 |
235MS |
190MS |
JDK Method调用
|
29188MS
|
4633MS
|
JDK Method调用(稍作优化)
|
5672MS
|
4262MS
|
Cglib FastMethod调用
|
5390MS
|
2787MS
|
得出一个感性的结果:
1.JDK反射效率是直接调用的一个数量级,差不多20倍
2.一个set方法的反射调用时间 = 4633ms / 1亿 / 3次 = 0.0154us
3.Cglib的fastmethod还是有优势的
最后,附上测试代码:
1 /**
2 * <pre>
3 * 本机测试结果(XP,双核,2G):
4 * 直接调用(LOOP=1亿): 235MS
5 * 反射调用(LOOP=1亿): 29188MS
6 * 反射调用(优化)(LOOP=1亿): 5672MS
7 * 放射调用(CGLIB)(LOOP=1亿):5390MS
8 *
9 * 服务器测试结果(linux xen虚拟机,5.5G内存;8核CPU):
10 * 直接调用(LOOP=1亿): 190MS
11 * 反射调用(LOOP=1亿): 4633MS
12 * 反射调用(优化)(LOOP=1亿): 4262MS
13 * 放射调用(CGLIB)(LOOP=1亿):2787MS
14 * </pre>
15 *
16 * @author Stone.J 2010-9-15 上午10:07:27
17 */
18 public class ReflectionTest {
19
20 private static final int DEFAULT_INT = 1;
21 private static final Integer DEFAULT_INTEGER = 1;
22 private static final String DEFAULT_STRING = "name";
23 private static final Object[] DEFAULT_INTS = { 1 };
24 private static final Object[] DEFAULT_INTEGERS = new Integer[] { 1 };
25 private static final Object[] DEFAULT_STRINGS = new String[] { "name" };
26
27 private static final Bean BEAN = new Bean();
28
29 private static final CachedMethod CACHED_METHOD = new CachedMethod();
30 private static final OptimizationCachedMethod OPTIMIZATION_CACHED_METHOD = new OptimizationCachedMethod();
31 private static final CglibCachedMethod CGLIB_CACHED_METHOD = new CglibCachedMethod();
32
33 private static final long LOOP = 1 * 10000 * 10000;
34
35 // 测试main
36 public static void main(String[] args) {
37 if (args.length != 1) {
38 System.out.println("args error.");
39 System.exit(1);
40 }
41 int tc = Integer.valueOf(args[0]);
42
43 long start = System.currentTimeMillis();
44 for (long i = 0; i < LOOP; i++) {
45 switch (tc) {
46 case 1:
47 // 直接调用
48 test();
49 break;
50 case 2:
51 // 反射调用
52 testReflection();
53 break;
54 case 3:
55 // 优化后反射调用
56 testOptimizationReflection();
57 break;
58 case 4:
59 // cglib反射调用
60 testCglibReflection();
61 break;
62 default:
63 System.out.println("tc error. must be [1-4]");
64 break;
65 }
66 }
67 long dur = System.currentTimeMillis() - start;
68 System.out.println(dur);
69 }
70
71 // 直接调用测试
72 public static void test() {
73 BEAN.setId(DEFAULT_INT);
74 BEAN.setCode(DEFAULT_INTEGER);
75 BEAN.setName(DEFAULT_STRING);
76 }
77
78 // 反射调用测试
79 public static void testReflection() {
80 try {
81 CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
82 CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
83 CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
84 } catch (Exception e) {
85 e.printStackTrace();
86 }
87 }
88
89 // 优化后反射调用测试
90 public static void testOptimizationReflection() {
91 try {
92 OPTIMIZATION_CACHED_METHOD.setId.invoke(BEAN, DEFAULT_INTS);
93 OPTIMIZATION_CACHED_METHOD.setCode.invoke(BEAN, DEFAULT_INTEGERS);
94 OPTIMIZATION_CACHED_METHOD.setName.invoke(BEAN, DEFAULT_STRINGS);
95 } catch (Exception e) {
96 e.printStackTrace();
97 }
98 }
99
100 // cglib反射调用测试
101 public static void testCglibReflection() {
102 try {
103 CGLIB_CACHED_METHOD.cglibSetId.invoke(BEAN, DEFAULT_INTS);
104 CGLIB_CACHED_METHOD.cglibSetCode.invoke(BEAN, DEFAULT_INTEGERS);
105 CGLIB_CACHED_METHOD.cglibSetName.invoke(BEAN, DEFAULT_STRINGS);
106 } catch (Exception e) {
107 e.printStackTrace();
108 }
109 }
110
111 /**
112 * <pre>
113 * 测试的bean
114 * 简单的int Integer String类型
115 * </pre>
116 *
117 * @author Stone.J 2010-9-15 上午10:40:40
118 */
119 public static class Bean {
120
121 private int id;
122 private Integer code;
123 private String name;
124
125 public int getId() {
126 return id;
127 }
128
129 public void setId(int id) {
130 this.id = id;
131 }
132
133 public Integer getCode() {
134 return code;
135 }
136
137 public void setCode(Integer code) {
138 this.code = code;
139 }
140
141 public String getName() {
142 return name;
143 }
144
145 public void setName(String name) {
146 this.name = name;
147 }
148
149 }
150
151 /**
152 * 反射测试需要:Cached Method
153 *
154 * @author Stone.J 2010-9-15 上午10:41:04
155 */
156 public static class CachedMethod {
157
158 public Method setId;
159 public Method setCode;
160 public Method setName;
161
162 {
163 try {
164 setId = Bean.class.getDeclaredMethod("setId", int.class);
165 setCode = Bean.class.getDeclaredMethod("setCode", Integer.class);
166 setName = Bean.class.getDeclaredMethod("setName", String.class);
167 } catch (Exception e) {
168 e.printStackTrace();
169 }
170 }
171
172 }
173
174 /**
175 * 反射测试需要:优化后的Cached Method
176 *
177 * @author Stone.J 2010-9-15 上午10:41:21
178 */
179 public static class OptimizationCachedMethod extends CachedMethod {
180
181 {
182 /** 所谓的优化 */
183 setId.setAccessible(true);
184 setCode.setAccessible(true);
185 setName.setAccessible(true);
186 }
187
188 }
189
190 /**
191 * 反射测试需要,使用cglib的fast method
192 *
193 * @author Stone.J 2010-9-15 上午10:51:53
194 */
195 public static class CglibCachedMethod extends CachedMethod {
196
197 public FastMethod cglibSetId;
198 public FastMethod cglibSetCode;
199 public FastMethod cglibSetName;
200
201 private FastClass cglibBeanClass = FastClass.create(Bean.class);
202
203 {
204 cglibSetId = cglibBeanClass.getMethod(setId);
205 cglibSetCode = cglibBeanClass.getMethod(setCode);
206 cglibSetName = cglibBeanClass.getMethod(setName);
207 }
208
209 }
210
211 }