Java 编程的动态性,第 8 部分: 用代码生成取代反射
2010-03-18 00:00:00 来源:WEB开发网性能检查
已经介绍了 Javassist 和 BCEL 版本的方法构造,现在可以试用它们以了解它们工作的情况。在运行时生成代码的根本理由是用一些更快的的东西取代反射,所以最好加入性能比较以了解在这方面的改进。为了更加有趣,我还将比较用两种框架构造 glue 类所用的时间。
清单 6 显示用于检查性能的测试代码的主要部分。 runReflection() 方法运行测试的反射部分, runAccess() 运行直接访问部分, run() 控制整个进程(包括打印时间结果)。 runReflection() 和 runAccess() 都取要执行的次数作为参数,这个参数是以命令行的形式传递的(使用的代码没有在清单中显示,但是包括在下载中)。 DirectLoader 类(在清单 6 的结尾)只提供了装载生成的类的一种容易的方式。
清单 6. 性能测试代码
/** Run timed loop using reflection for access to value. */
private int runReflection(int num, Method gmeth, Method smeth,
Object obj) {
int value = 0;
try {
Object[] gargs = new Object[0];
Object[] sargs = new Object[1];
for (int i = 0; i < num; i++) {
// messy usage of Integer values required in loop
Object result = gmeth.invoke(obj, gargs);
value = ((Integer)result).intValue() + 1;
sargs[0] = new Integer(value);
smeth.invoke(obj, sargs);
}
} catch (Exception ex) {
ex.printStackTrace(System.err);
System.exit(1);
}
return value;
}
/** Run timed loop using generated class for access to value. */
private int runAccess(int num, IAccess access, Object obj) {
access.setTarget(obj);
int value = 0;
for (int i = 0; i < num; i++) {
value = access.getValue() + 1;
access.setValue(value);
}
return value;
}
public void run(String name, int count) throws Exception {
// get instance and access methods
HolderBean bean = new HolderBean();
String pname = name;
char lead = pname.charAt(0);
pname = Character.toUpperCase(lead) + pname.substring(1);
Method gmeth = null;
Method smeth = null;
try {
gmeth = HolderBean.class.getDeclaredMethod("get" + pname,
new Class[0]);
smeth = HolderBean.class.getDeclaredMethod("set" + pname,
new Class[] { int.class });
} catch (Exception ex) {
System.err.println("No methods found for property " + pname);
ex.printStackTrace(System.err);
return;
}
// create the access class as a byte array
long base = System.currentTimeMillis();
String cname = "IAccess$impl_HolderBean_" + gmeth.getName() +
"_" + smeth.getName();
byte[] bytes = createAccess(HolderBean.class, gmeth, smeth, cname);
// load and construct an instance of the class
Class clas = s_classLoader.load(cname, bytes);
IAccess access = null;
try {
access = (IAccess)clas.newInstance();
} catch (IllegalAccessException ex) {
ex.printStackTrace(System.err);
System.exit(1);
} catch (InstantiationException ex) {
ex.printStackTrace(System.err);
System.exit(1);
}
System.out.println("Generate and load time of " +
(System.currentTimeMillis()-base) + " ms.");
// run the timing comparison
long start = System.currentTimeMillis();
int result = runReflection(count, gmeth, smeth, bean);
long time = System.currentTimeMillis() - start;
System.out.println("Reflection took " + time +
" ms. with result " + result + " (" + bean.getValue1() +
", " + bean.getValue2() + ")");
bean.setValue1(0);
bean.setValue2(0);
start = System.currentTimeMillis();
result = runAccess(count, access, bean);
time = System.currentTimeMillis() - start;
System.out.println("Generated took " + time +
" ms. with result " + result + " (" + bean.getValue1() +
", " + bean.getValue2() + ")");
}
/** Simple-minded loader for constructed classes. */
protected static class DirectLoader extends SecureClassLoader
{
protected DirectLoader() {
super(TimeCalls.class.getClassLoader());
}
protected Class load(String name, byte[] data) {
return super.defineClass(name, data, 0, data.length);
}
}
更多精彩
赞助商链接