基于javassist進(jìn)行動(dòng)態(tài)編程過(guò)程解析
今天在研究dubbo時(shí),發(fā)現(xiàn)一個(gè)新的知識(shí)點(diǎn),可以使用javassist包進(jìn)行動(dòng)態(tài)編程,hibernate也使用該包進(jìn)行編程。晚上百度了很多資料,將它的特性以代碼的形式展現(xiàn)出來(lái)。
package com.zhi.demo;
import java.lang.reflect.Field;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.Loader;
import javassist.Modifier;
import javassist.bytecode.AccessFlag;
/**
* Javassist動(dòng)態(tài)編程測(cè)試
*
* @date 2019年03月11日23:00:33
*
*/
public class JavassistTest {
public static void main(String[] args) {
try {
test();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void test() throws Exception {
System.out.println("-------------------新增類------------------");
ClassPool pool = ClassPool.getDefault();
// 創(chuàng)建類
CtClass ct = pool.makeClass("com.zhi.Person");
// 讓類實(shí)現(xiàn)Cloneable接口
ct.setInterfaces(new CtClass[] { pool.makeInterface("java.lang.Cloneable") });
// 添加一個(gè)int類型的共有屬性
CtField fieldId = new CtField(CtClass.intType, "id", ct);
fieldId.setModifiers(AccessFlag.PUBLIC);
ct.addField(fieldId);
// 添加一個(gè)默認(rèn)構(gòu)造器
CtConstructor constructor1 = CtNewConstructor.make("public Person(){this.id=1;}", ct);
ct.addConstructor(constructor1);
// 添加方法
CtMethod helloM = CtNewMethod
.make("public void hello(String des){System.out.println(\"執(zhí)行hello方法,\"+des+\",我的id是\"+this.id);}", ct);
ct.addMethod(helloM);
// 將生成的.class文件保存到磁盤(pán)
ct.writeFile();
// 加載目標(biāo)類,可用ct.toClass()或new Loader(pool).loadClass()
Class<?> clazz = ct.toClass();
// Class<?> clazz = new Loader(pool).loadClass("com.zhi.Person");
// 輸出類基本信息
System.out.println("包名:" + clazz.getPackageName());
System.out.println("類名:" + clazz.getName());
System.out.println("簡(jiǎn)要類名:" + clazz.getSimpleName());
System.out.println("限定符:" + Modifier.toString(clazz.getModifiers()));
System.out.println("繼承類:" + clazz.getSuperclass().getName());
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("屬性名稱:" + field.getName() + ",屬性類型:" + field.getType() + ",限定符:"
+ Modifier.toString(field.getModifiers()));
}
// 構(gòu)造一個(gè)對(duì)象,并執(zhí)行hello方法
Object ob = clazz.getDeclaredConstructor().newInstance();
clazz.getMethod("hello", String.class).invoke(ob, "張三");
// 解凍(執(zhí)行toClass后會(huì)自動(dòng)凍結(jié))
ct.defrost();
System.out.println("-------------------修改類------------------");
// 添加一個(gè)String類型的私有屬性
CtField fieldName = new CtField(pool.get(String.class.getName()), "name", ct);
fieldName.setModifiers(AccessFlag.PRIVATE);
ct.addField(fieldName);
// 添加帶參的構(gòu)造函數(shù)
CtConstructor constructor2 = new CtConstructor(new CtClass[] { pool.get(String.class.getName()) }, ct);
constructor2.setModifiers(Modifier.PUBLIC);
constructor2.setBody("{this.name=$1;}");
ct.addConstructor(constructor2);
ct.addMethod(CtNewMethod.make("public void setName(String name){this.name=name;}", ct));
ct.addMethod(CtNewMethod.make("public String getName(){return this.name;}", ct));
ct.writeFile();
// 加載類,若前面已用ct.toClass()進(jìn)行加載,則這里不能再用ct.toClass()加載,否則會(huì)出錯(cuò),同一個(gè)加載不能2次加載同一個(gè)類
clazz = new Loader(pool).loadClass("com.zhi.Person");
fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println("屬性名稱:" + field.getName() + ",屬性類型:" + field.getType() + ",限定符:"
+ Modifier.toString(field.getModifiers()));
}
ob = clazz.getDeclaredConstructor(String.class).newInstance("馬云");
System.out.println("執(zhí)行g(shù)etName方法得到的值為:" + clazz.getMethod("getName").invoke(ob));
}
}
執(zhí)行上面代碼輸出結(jié)果為:
-------------------新增類------------------ 包名:com.zhi 類名:com.zhi.Person 簡(jiǎn)要類名:Person 限定符:public 繼承類:java.lang.Object 屬性名稱:id,屬性類型:int,限定符:public 執(zhí)行hello方法,張三,我的id是1 -------------------修改類------------------ 屬性名稱:id,屬性類型:int,限定符:public 屬性名稱:name,屬性類型:class java.lang.String,限定符:private 執(zhí)行g(shù)etName方法得到的值為:馬云
說(shuō)明:
$0,$1,$2:分別代表this,第一個(gè)參數(shù),第二個(gè)參數(shù)
$r:方法返回值的類型。
$_:方法返回值
依賴包
<dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.24.1-GA</version> </dependency>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
攜程Apollo(阿波羅)安裝部署以及java整合實(shí)現(xiàn)
這篇文章主要介紹了攜程Apollo(阿波羅)安裝部署以及java整合實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08
java Class.getSimpleName() 詳解及用法
這篇文章主要介紹了java Class.getSimpleName() 詳解及用法的相關(guān)資料,需要的朋友可以參考下2017-02-02
java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作
這篇文章主要介紹了java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
Java之注解@Data和@ToString(callSuper=true)解讀
在使用Lombok庫(kù)的@Data注解時(shí),若子類未通過(guò)@ToString(callSuper=true)注明包含父類屬性,toString()方法只打印子類屬性,解決方法:1. 子類重寫(xiě)toString方法;2. 子類使用@Data和@ToString(callSuper=true),父類也應(yīng)使用@Data2024-11-11
SpringBoot前后端交互、全局異常處理之后端異常信息拋到前端顯示彈窗
Spring Boot是一個(gè)用于構(gòu)建獨(dú)立的、基于生產(chǎn)級(jí)別的Spring應(yīng)用程序的框架,下面這篇文章主要給大家介紹了關(guān)于SpringBoot前后端交互、全局異常處理之后端異常信息拋到前端顯示彈窗的相關(guān)資料,需要的朋友可以參考下2024-08-08
java實(shí)現(xiàn)簡(jiǎn)單猜數(shù)字游戲
這篇文章主要介紹了java實(shí)現(xiàn)簡(jiǎn)單猜數(shù)字游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
Java基礎(chǔ)學(xué)習(xí)之實(shí)參和形參
這篇文章主要介紹了Java基礎(chǔ)學(xué)習(xí)之實(shí)參形參,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有一定的幫助,需要的朋友可以參考下2021-05-05
java中ThreadLocal的應(yīng)用場(chǎng)景實(shí)例分析
在本篇文章里小編給大家整理的是一篇關(guān)于java中ThreadLocal的應(yīng)用場(chǎng)景實(shí)例分析,對(duì)此有興趣的朋友們可以學(xué)習(xí)參考下。2021-02-02
Spring?RestTemplate如何利用攔截器打印請(qǐng)求參數(shù)和返回狀態(tài)
這篇文章主要介紹了Spring?RestTemplate如何利用攔截器打印請(qǐng)求參數(shù)和返回狀態(tài)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07

