Java 動態(tài)特性二:字節(jié)碼操作

java本身動態(tài)性的兩種實現(xiàn)方式:反射字節(jié)碼操作

字節(jié)碼操作:可以實現(xiàn)動態(tài)生成一個類(.class文件)和動態(tài)的修改類的結(jié)構(gòu);可以去改變一個類。
反射:去動態(tài)的執(zhí)行類的內(nèi)容,不能改變類。一個是改變,一個是執(zhí)行;多數(shù)情況下兩者配合使用。

反射中有Class、 Method、Field、Constructor等類,相似在字節(jié)碼操作中有CtClass、CtMethod、CtField、CtConstructor等與之相對應(yīng)。 Ct(Compile time)。

MakeNewClass:利用動態(tài)字節(jié)碼操作生成一個新的類;
ChangeClass :去改變一個類的結(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的動態(tài)性中對字節(jié)碼的操作,
 * 利用javasisit生成一個新的.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)建一個類
        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é)碼動態(tài)添加一個方法,并且執(zhí)行這個方法
     * @throws Exception
     */
    public static void test1() throws Exception{

        ClassPool classPool = ClassPool.getDefault();
        String path = "com.test.reflect.User";
        CtClass ctClass = classPool.get(path);
        
        // 給類添加一個新方法
        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é)碼動態(tài)添加動態(tài)給一個方法的前面或者后面添加方法,并且執(zhí)行這個方法
     * @throws Exception
     */
    public static void test2() throws Exception{
        
        ClassPool classPool = ClassPool.getDefault();
        String path = "com.test.reflect.User";
        CtClass ctClass = classPool.get(path);
        // 修改方法,在某個方法的前面或者后面加入新的方法;像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;
    }
    
    // 類中一個普通的方法
    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;
    }
    
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,537評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,936評論 25 709
  • 迷迷糊糊的感覺和朋友在一起,卻又想不起來,腦袋一片空白,像是喝醉了斷片兒,只記得天黑黢黢的,天空中連啟明星也沒有亮...
    魑魅魍魎吃下糯米粽子閱讀 914評論 0 9

友情鏈接更多精彩內(nèi)容