INT_ARGS, null, "setValue", cname, ilist, pgen);
addMethod(mgen, cgen);
// return bytecode of completed class
return cgen.getJavaClass().getBytes();
}
Java编程的动态性,第8部分: 用代码生成取代反射(4)
时间:2011-04-09 IBM Dennis M. Sosnoski
性能检查
已经介绍了 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_"
|