最近学习ASM,非常感谢哈库纳大佬的指点,推荐几篇大佬写的ASM相关博客
深入字节码 -- ASM 关键接口 ClassVisitor
深入字节码 -- ASM 关键接口 MethodVisitor
同时强烈推荐大佬的框架:Hasor
下面直接上代码,初学者,有不对的地方请大佬们指正!
创建java类:
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, className, null, "java/lang/Object", null);
cw.visitSource(className + ".java", null);
生成<init>函数:
/**
* 生成构造函数
*/
private void generatedInit(ClassWriter cw){
// 构造函数
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label initLabel = new Label();
mv.visitLabel(initLabel);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
为javaBean添加字段:
// 添加字段,这里添加的是public String类型的字段
cw.visitField(ACC_PUBLIC, fieldName, "Ljava/lang/String;", null, null);
写入get函数:
/**
* 生成get方法
*/
private void generatedGet(ClassWriter cw, String name, String className){
// 生成get函数,不接收参数,有返回值
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get" + firstLetterToUpperCase(name), "()Ljava/lang/String;", null, null);
mv.visitCode();
Label label = new Label();
mv.visitLabel(label);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, className, name, "Ljava/lang/String;");
mv.visitInsn(ARETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
写入set函数:
/**
* 生成set方法
*/
private void generatedSet(ClassWriter cw, String name, String className){
// 生成set函数
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set" + firstLetterToUpperCase(name), "(Ljava/lang/String;)V", null, null);
mv.visitCode();
Label mainLabel = new Label();
mv.visitLabel(mainLabel);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, className, name, "Ljava/lang/String;");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
首字母转换大写:
private String firstLetterToUpperCase(String name){
char[] cs = name.toCharArray();
cs[0] -= (cs[0] > 96 && cs[0] < 123) ? 32 : 0;
return String.valueOf(cs);
}
将生成的ClassWriter字节数组加载为Class:
ClassLoader.defineClass(className, data, 0, data.length);
使用javap -c,查看生成的指令文件:
public class User {
public java.lang.String name;
public java.lang.String nickName;
public java.lang.String userName;
public java.lang.String getName();
Code:
0: aload_0
1: getfield #11 // Field name:Ljava/lang/String;
4: areturn
public void setName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #11 // Field name:Ljava/lang/String;
5: return
public java.lang.String getNickName();
Code:
0: aload_0
1: getfield #17 // Field nickName:Ljava/lang/String;
4: areturn
public void setNickName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #17 // Field nickName:Ljava/lang/String;
5: return
public java.lang.String getUserName();
Code:
0: aload_0
1: getfield #22 // Field userName:Ljava/lang/String;
4: areturn
public void setUserName(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield #22 // Field userName:Ljava/lang/String;
5: return
public User();
Code:
0: aload_0
1: invokespecial #27 // Method java/lang/Object."<init>":()V
4: return
}
测试运行:
public static void main(String[] args) {
try {
List<String> fields = new ArrayList<>();
fields.add("name");
fields.add("nickName");
fields.add("userName");
GeneratedBean generatedBean = new GeneratedBean();
generatedBean.generatedBean(fields, "User");
generatedBean.setMethod("nickName", "hello java");
Object invoke = generatedBean.getMethod("nickName");
System.out.println(invoke.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
运行后输出结果:
hello java
完整代码: