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
}