创建类
构造对象
使用DummyClass创建class
1. DummyClass dummy = new DummyClass();
2. DummyClass dummy = new DummyClass("asmsupport.test.Test");
3. DummyClass dummy = new DummyClass("asmsupport.test", "Test");
上面三种方式,第一种仅仅知识啊创建一个DummyClass对象,第二种方式在创建对象的同时赋予的接口的全限定名。第三种方式将包名和类名分开指定。
设置类名
如果在构造DummyInterface的同时已经赋予了包名和类名,那么这里就可以不用为其设置。当然也可以在这里重新设置,将以前的值覆盖。
dummy.package_("asmsupport.test").name("Test")
设置接口的访问权限
接口的访问控制权限
dummy.public_() : 设置成public
dummy.protected_(); 设置为protected
dummy.default_() : 设置成默认
dummy.private_() : 设置为private
添加父类型
dummy.extends_(ArrayList.class);
添加接口
dummy.implements_(List.class, Cloneable.class);
创建Field
DummyField field = dummy.newField(String.class, "FIELD");
上面的代码为类创建了名为FIELD的字段。默认情况下使用的是默认的修饰符,上面的代码生成的对应java代码如下:
设置field名
通过这个方法可以重新设置field名
设置field类型
通过这个方法可以重新设置field的类型
修改field访问控制符号
默认为default。
field.public_();
field.protected_();
field.default_();
field.private_();
其他修饰
field.transient_(); //增加transient修饰
field.static_(); //设置为static
field.volatile_(); //增加volatile修饰
field.final_(); //增加final修饰
Field赋值1
上面看到了newField返回的是DummyField对象。可以通过这个对象的一系列重载方法val()为其赋值。但是这样只允许根据field类型为其赋予基本的值。比如上面我们为FIELD赋值为“asmsupport”
Field赋值2
如果希望类型通过方法调用的方式赋值比如下面的代码
public String FIELD = String.valueOf(100);
那么赋值就需要在静态程序块中通过assign方法赋值,为什么在静态程序块可以参考文档site/bytecode/init_clinit.md
创建方法
这里将介绍如何创建接口的方法。通过DummyInterface的newMethod方法创
DummyMethod method = dummy.newMethod("test");
通过上面的代码就已经告诉asmsupport了,创建一个test的方法,但是test方法仅仅是如下内容
由于是接口方法,所以public的修饰符是无法改变的,但是方法的返回类型已经参数列表是可以改变了。
修改返回类型
method.return_(Stirng.class);
修改参数列表
method.argTypes(int.class, double.class);
设置方法参数名
mehtod.argNames("i", "d");
抛出捕获
method.throws_(RuntimeException.class, IOException.class);
修改访问权限
method.public_();
method.protected_();
method.default_();
method.private_();
修改其他修饰
method.abstract_(); //增加abstract修饰
method.static_(); //设置为static
method.synchronized_(); //增加synchronized修饰
method.final_(); //增加final修饰
method.native_(); //增加native修饰
method.strictfp_(); //增加strictfp修饰
增加方法体
method.body(new MethodBody() {
@Override
public void body(LocalVariable... args) {
//DO method logic here.
}
});
创建构造方法
DummyConstructor constructor = dummy.newConstructor();
修改参数列表
constructor.argTypes(int.class, double.class);
设置方法参数名
constructor.argNames("i", "d");
抛出捕获
constructor.throws_(RuntimeException.class, IOException.class);
修改构造方法修饰符
constructor.public_();
constructor.protected_();
constructor.default_();
constructor.private_();
增加方法体
constructor.body(new ConstructorBody(){
@Override
public void body(LocalVariable... args) {
supercall();
return_();
}
});
注意如果需要调用父类的构造方法则需要通过supercall方法调用。
创建静态程序块
dummy.newStaticBlock(new StaticBlockBody() {
@Override
public void body(){
GlobalVariable FIELD = getMethodOwner().field("FIELD");
assign(FIELD, call(String.class, "valueOf", val(100)));
GlobalVariable out = defType(System.class).field("out");
call(out, "println", val("Hello ASMSupport"))
return_();
}
});
在这里我们创建出了一个静态程序块,在程序块中为我们在上面创建的FIELD赋值。最后我们显式的调用了return。
设置javaversion
我们会根据当前使用的JDK版本自动选择class的版本,但是也可以显式的设置class版本,通过下面的方式
dummy.setJavaVersion(Opcodes.V1_5)
设置ClassLoader
我们内置ClassLoader来完成我们生成的class的字节数组到class对象,当然也允许自定义classloader通过下面的方法
dummy.setClassLoader(classloader);
设置class文件输出目录
dummy.setClassOutPutPath("../classes/");
设置这个属性,我们生成的class将会输出到指定目录,这样我们可以通过反编译大致看下class内容是否和预期相同。
开始创建
Class<?> clazz = dummy.build();