java反射效率
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 }
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 }