java本身動(dòng)態(tài)性的兩種實(shí)現(xiàn)方式:反射和字節(jié)碼操作
字節(jié)碼操作:可以實(shí)現(xiàn)動(dòng)態(tài)生成一個(gè)類(.class文件)
和動(dòng)態(tài)的修改類的結(jié)構(gòu)帘饶;可以去改變一個(gè)類。
反射:去動(dòng)態(tài)的執(zhí)行類的內(nèi)容渣叛,不能改變類哟玷。一個(gè)是改變,一個(gè)是執(zhí)行仅乓;多數(shù)情況下兩者配合使用赖舟。
反射中有Class、 Method夸楣、Field宾抓、Constructor等類,相似在字節(jié)碼操作中有CtClass豫喧、CtMethod石洗、CtField、CtConstructor等與之相對(duì)應(yīng)紧显。 Ct(Compile time)讲衫。
MakeNewClass:利用動(dòng)態(tài)字節(jié)碼操作生成一個(gè)新的類;
ChangeClass :去改變一個(gè)類的結(jié)構(gòu)
User: 需要改變的類
package com.test.byteCode;
import java.io.IOException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
/**
* java的動(dòng)態(tài)性中對(duì)字節(jié)碼的操作孵班,
* 利用javasisit生成一個(gè)新的.class文件
* @author zhb
*
*/
public class MakeNewClass {
public static void main(String[] args) throws CannotCompileException, IOException {
ClassPool pool = ClassPool.getDefault();
String className = "com.test.reflect.User";
// 用類的全路徑創(chuàng)建一個(gè)類
CtClass ctClass = pool.makeClass(className);
// 給類創(chuàng)建屬性
CtField ctField = CtField.make("private int id;", ctClass);
// 給類添加屬性
ctClass.addField(ctField);
// 給類創(chuàng)建構(gòu)造方法
// 創(chuàng)建有參的構(gòu)造方法
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType}, ctClass);
ctConstructor.setBody("this.id = id;");
// 給類添加構(gòu)造方法
ctClass.addConstructor(ctConstructor);
// 給類創(chuàng)建方法
CtMethod ctMethod1 = CtMethod.make("private void setId(String id){this.id = id;}", ctClass);
CtMethod ctMethod2 = CtMethod.make("private String getId(){return id;}", ctClass);
CtMethod ctMethod3 = CtMethod.make("public void sayHello(){System.out.println(\"你好\");}", ctClass);
// 給類添加方法
ctClass.addMethod(ctMethod1);
ctClass.addMethod(ctMethod2);
ctClass.addMethod(ctMethod3);
// 生成class文件涉兽,到D盤Myclass的文件夾下
ctClass.writeFile("E:/Myclass");
System.out.println("class文件創(chuàng)建成功");
}
}
package com.test.byteCode;
import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
/**
* 更改User的class文件的內(nèi)容
* @author zhb
*
*/
public class ChangeClass {
/**
* 用字節(jié)碼動(dòng)態(tài)添加一個(gè)方法,并且執(zhí)行這個(gè)方法
* @throws Exception
*/
public static void test1() throws Exception{
ClassPool classPool = ClassPool.getDefault();
String path = "com.test.reflect.User";
CtClass ctClass = classPool.get(path);
// 給類添加一個(gè)新方法
CtMethod ctMethod = CtMethod.make("public int add(int a, int b){return a+b;}", ctClass);
ctClass.addMethod(ctMethod);
// 通過反射執(zhí)行剛剛加入的add方法
// ctClass轉(zhuǎn)成反射類
Class clazz = ctClass.toClass();
Object obj = clazz.newInstance();
Method method = clazz.getMethod("add", int.class, int.class);
// 執(zhí)行剛剛加入的add方法
Object result = method.invoke(obj, 8, 4);
ctClass.defrost();
System.out.println(result);
}
/**
* 用字節(jié)碼動(dòng)態(tài)添加動(dòng)態(tài)給一個(gè)方法的前面或者后面添加方法篙程,并且執(zhí)行這個(gè)方法
* @throws Exception
*/
public static void test2() throws Exception{
ClassPool classPool = ClassPool.getDefault();
String path = "com.test.reflect.User";
CtClass ctClass = classPool.get(path);
// 修改方法枷畏,在某個(gè)方法的前面或者后面加入新的方法;像spring AOP
// 獲取原有的方法房午,hello
CtMethod ctMethod = ctClass.getDeclaredMethod("hello", new CtClass[]{classPool.get("java.lang.String")});
ctMethod.insertBefore("System.out.println(\"方法之前執(zhí)行\(zhòng)");");
ctMethod.insertAfter("System.out.println(\"方法之后執(zhí)行\(zhòng)");");
Class clazz = ctClass.toClass();
Object obj = clazz.newInstance();
Method method = clazz.getMethod("hello", String.class);
method.invoke(obj,"張三");
}
public static void main(String[] args) throws Exception {
test1();
// test2();
}
}
package com.test.reflect;
public class User {
private int id;
private String name;
// 無參的構(gòu)造方法矿辽,容易被忘記
public User(){
}
//有參的構(gòu)造方法
public User(int id, String name){
this.id = id;
this.name = name;
}
// 類中一個(gè)普通的方法
public String hello(String name){
System.out.println("hello:"+ name);
return "方法調(diào)用成功";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}