Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | [email protected] |
目录
基本使用
原始类
package com.bqt.test;
public class Person {
public int hello(String s) {
return s.length();
}
public String hello2(String s) {
return s;
}
}
创建新类
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("com.bqt.test.User");
//创建属性
cc.addField(CtField.make("private int id;", cc));
cc.addField(CtField.make("private String name;", cc));
//创建方法
cc.addMethod(CtMethod.make("public String getName(){return name;}", cc));
cc.addMethod(CtMethod.make("public void setName(String name){this.name = name;}", cc));
//添加构造器
CtConstructor constructor = new CtConstructor(new CtClass[] { CtClass.intType, pool.get("java.lang.String") }, cc);
constructor.setBody("{this.id=id;this.name=name;}");
cc.addConstructor(constructor);
cc.writeFile("d:/test");
生成的类经反编译后的源码为:
package com.bqt.test;
public class User {
private int id;
private String name;
public User(int paramInt, String paramString) {
this.id = this.id;
this.name = this.name;
}
public String getName() {
return this.name;
}
public void setName(String paramString) {
this.name = paramString;
}
}
获取类信息
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.Person");
byte[] bytes = cc.toBytecode();//得到字节码
System.out.println(bytes.length);
System.out.println(cc.getName());//获取类名
System.out.println(cc.getSimpleName());//获取简要类名
System.out.println(cc.getSuperclass().getName());//获取父类
System.out.println(Arrays.toString(cc.getInterfaces()));//获取接口
for (CtConstructor con : cc.getConstructors()) {//获取构造方法
System.out.println("构造方法 "+con.getLongName());
}
for (CtMethod method : cc.getMethods()) {//获取方法
System.out.println(method.getLongName());
}
打印内容:
562
com.bqt.test.Person
Person
java.lang.Object
[]
构造方法 com.bqt.test.Person()
java.lang.Object.equals(java.lang.Object)
java.lang.Object.finalize()
com.bqt.test.Person.hello2(java.lang.String)
java.lang.Object.toString()
java.lang.Object.getClass()
java.lang.Object.notifyAll()
java.lang.Object.hashCode()
java.lang.Object.wait()
java.lang.Object.notify()
com.bqt.test.Person.hello(java.lang.String)
java.lang.Object.wait(long)
java.lang.Object.wait(long,int)
java.lang.Object.clone()
添加方法
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.Person");
//方式一
CtMethod cm1 = CtMethod.make("public int add1(int a, String b){return a+b.length();}", cc);//第一种方式,完整的方法以字符串形式传递过去
cc.addMethod(cm1); //cc.removeMethod(cm3) 删除一个方法
//方式二
CtClass[] parameters = new CtClass[] { CtClass.intType, pool.get("java.lang.String") };
CtMethod cm2 = new CtMethod(CtClass.intType, "add2", parameters, cc);//第二种方式,返回值类型,方法名,参数,对象
cm2.setModifiers(Modifier.PUBLIC);//访问范围
cm2.setBody("{return $1+$2.length();}");//方法体
cc.addMethod(cm2);
//通过反射调用方法
Class clazz = cc.toClass(); //注意,如果使用 JDK9 以下的JDK ,同时使用 3.20.0-GA 以上版本的 Javassist,会报 StackWalker 异常
Object obj = clazz.newInstance();//通过调用无参构造器,生成新的对象
Method m1 = clazz.getDeclaredMethod("add1", int.class, String.class);
System.out.println(m1.invoke(obj, 1, "包青天"));
Method m2 = clazz.getDeclaredMethod("add2", int.class, String.class);
System.out.println(m2.invoke(obj, 2, "包青天"));
cc.writeFile("D:/test");//保存到指定位置
生成的类经反编译后的源码为:
package com.bqt.test;
public class Person {
public int hello(String s) {
return s.length();
}
public String hello2(String s) {
return s;
}
public int add1(int paramInt, String paramString) {
return paramInt + paramString.length();
}
public int add2(int paramInt, String paramString) {
return paramInt + paramString.length();
}
}
修改方法
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.Person");
//方式一
CtMethod cm = cc.getDeclaredMethod("hello", new CtClass[] { pool.get("java.lang.String") });
cm.insertBefore("System.out.println(\"调用前2\");");//调用前
cm.insertBefore("System.out.println(\"调用前1\");");
cm.insertAt(20094, "System.out.println(\"在指定行插入代码\");");//貌似行号胡乱写也可以
cm.insertAfter("System.out.println(\"调用后1\");");//调用后
cm.insertAfter("System.out.println(\"调用后2\");");//调用后
//方式二
CtMethod cm2 = cc.getDeclaredMethod("hello2", new CtClass[] { pool.get("java.lang.String") });
cm2.setBody("{" + // 你只需要正常写代码逻辑就可以了,复制过来时,一些IDE,比如AS会自动帮你添加转义字符
"if ($1 == null) {\n" + //$0代表的是this,$1代表方法参数的第一个参数、$2代表方法参数的第二个参数
"\treturn \"\";\n" + //
"}\n" + //
"return \"你好:\" + $1;" + //
"}");
//通过反射调用方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method m = clazz.getDeclaredMethod("hello", String.class);
System.out.println(m.invoke(obj, "包青天"));
Method m2 = clazz.getDeclaredMethod("hello2", String.class);
System.out.println(m2.invoke(obj, "包青天"));
cc.writeFile("D:/test");//保存到指定位置
生成的类经反编译后的源码为:
package com.bqt.test;
import java.io.PrintStream;
public class Person {
public int hello(String s) {
System.out.println("调用前1");
System.out.println("调用前2");
System.out.println("在指定行插入代码");
int i = s.length();
System.out.println("调用后1");
int j = i;
System.out.println("调用后2");
return j;
}
public String hello2(String paramString) {
if (paramString == null) {
return "";
}
return "你好:" + paramString;
}
}
添加属性
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.Person");
//方式一
CtField cf = new CtField(CtClass.intType, "age", cc);
cf.setModifiers(Modifier.PRIVATE);
cc.addField(cf);
cc.addMethod(CtNewMethod.getter("getAge", cf));
cc.addMethod(CtNewMethod.setter("setAge", cf));
//方式二
CtField cf2 = CtField.make("private String name;", cc);
cc.addField(cf2);
cc.addMethod(CtNewMethod.getter("getName", cf2)); //快捷的添加get/set方法
cc.addMethod(CtNewMethod.setter("setName", cf2));
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
System.out.println(clazz.getDeclaredField("age"));
System.out.println(clazz.getDeclaredField("name"));
clazz.getDeclaredMethod("setAge", int.class).invoke(obj, 16);
Object resutl = clazz.getDeclaredMethod("getAge", null).invoke(obj, null);
System.out.println(resutl);
cc.writeFile("D:/test");//保存到指定位置
生成的类经反编译后的源码为:
package com.bqt.test;
public class Person {
private int age;
private String name;
public int hello(String s) {
return s.length();
}
public String hello2(String s) {
return s;
}
public int getAge() {
return this.age;
}
public void setAge(int paramInt) {
this.age = paramInt;
}
public String getName() {
return this.name;
}
public void setName(String paramString) {
this.name = paramString;
}
}
实现动态代理
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.bqt.test.Person");
ProxyFactory factory = new ProxyFactory();//代理类工厂
factory.setSuperclass(cc.toClass());//设置父类,ProxyFactory将会动态生成一个类,继承该父类
//设置过滤器,判断哪些方法调用需要被拦截
factory.setFilter(new MethodFilter() {
@Override
public boolean isHandled(Method m) {
return m.getName().startsWith("hello");
}
});
Class<?> clazz = factory.createClass();//创建代理类型
Person proxy = (Person) clazz.newInstance();//创建代理实例
//设置代理处理方法
((ProxyObject) proxy).setHandler(new MethodHandler() {
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
System.out.println(thisMethod.getName() + "被调用了");
try {
Object ret = proceed.invoke(self, args);//thisMethod为被代理方法,proceed为代理方法,self为代理实例,args为方法参数
System.out.println("返回值: " + ret);
return ret;
} finally {
System.out.println(thisMethod.getName() + "调用完毕");
}
}
});
//测试
proxy.hello("包青天");
System.out.println(proxy.getClass().getName()); //com.bqt.test.Person_$$_jvstee7_0
打印日志:
hello被调用了
返回值: 3
hello调用完毕
com.bqt.test.Person_$$_jvstee7_0
2019-1-7