Java 编程的动态性,第 8 部分: 用代码生成取代反射
2010-03-18 00:00:00 来源:WEB开发网我不准备详细讨论这些代码,因为如果您一直跟着学习本系列,这里的大多数操作都是所熟悉的(如果您 还没有 看过本系列,请现在阅读 第 5 部分,了解使用 Javassist 的概述)。
用 BCEL 生成
用 BCEL 生成 清单 2 IAccess 的实现类不像使用 Javassist 那样容易,但是也不是很复杂。清单 5 给出了相应的代码。这段代码使用与清单 4 Javassist 代码相同的一组操作,但是运行时间要长一些,因为需要为 BCEL 拼出每一个字节码指令。与使用 Javassist 时一样,我将跳过实现的细节(如果有不熟悉的地方,请参阅 第 7 部分对 BCEL 的概述)。
清单 5. BCEL glue 类构造
/** Parameter types for call with single int value. */
private static final Type[] INT_ARGS = { Type.INT };
/** Utility method for adding constructed method to class. */
private static void addMethod(MethodGen mgen, ClassGen cgen) {
mgen.setMaxStack();
mgen.setMaxLocals();
InstructionList ilist = mgen.getInstructionList();
Method method = mgen.getMethod();
ilist.dispose();
cgen.addMethod(method);
}
protected byte[] createAccess(Class tclas,
java.lang.reflect.Method gmeth, java.lang.reflect.Method smeth,
String cname) {
// build generators for the new class
String tname = tclas.getName();
ClassGen cgen = new ClassGen(cname, "java.lang.Object",
cname + ".java", Constants.ACC_PUBLIC,
new String[] { "IAccess" });
InstructionFactory ifact = new InstructionFactory(cgen);
ConstantPoolGen pgen = cgen.getConstantPool();
//. add target object field to class
FieldGen fgen = new FieldGen(Constants.ACC_PRIVATE,
new ObjectType(tname), "m_target", pgen);
cgen.addField(fgen.getField());
int findex = pgen.addFieldref(cname, "m_target",
Utility.getSignature(tname));
// create instruction list for default constructor
InstructionList ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(ifact.createInvoke("java.lang.Object", "<init>",
Type.VOID, Type.NO_ARGS, Constants.INVOKESPECIAL));
ilist.append(InstructionFactory.createReturn(Type.VOID));
// add public default constructor method to class
MethodGen mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, null, "<init>", cname, ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for setTarget method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(InstructionConstants.ALOAD_1);
ilist.append(new CHECKCAST(pgen.addClass(tname)));
ilist.append(new PUTFIELD(findex));
ilist.append(InstructionConstants.RETURN);
// add public setTarget method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
new Type[] { Type.OBJECT }, null, "setTarget", cname,
ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for getValue method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(new GETFIELD(findex));
ilist.append(ifact.createInvoke(tname, gmeth.getName(),
Type.INT, Type.NO_ARGS, Constants.INVOKEVIRTUAL));
ilist.append(InstructionConstants.IRETURN);
// add public getValue method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.INT,
Type.NO_ARGS, null, "getValue", cname, ilist, pgen);
addMethod(mgen, cgen);
// create instruction list for setValue method
ilist = new InstructionList();
ilist.append(InstructionConstants.ALOAD_0);
ilist.append(new GETFIELD(findex));
ilist.append(InstructionConstants.ILOAD_1);
ilist.append(ifact.createInvoke(tname, smeth.getName(),
Type.VOID, INT_ARGS, Constants.INVOKEVIRTUAL));
ilist.append(InstructionConstants.RETURN);
// add public setValue method
mgen = new MethodGen(Constants.ACC_PUBLIC, Type.VOID,
INT_ARGS, null, "setValue", cname, ilist, pgen);
addMethod(mgen, cgen);
// return bytecode of completed class
return cgen.getJavaClass().getBytes();
}
更多精彩
赞助商链接