Java學習之動態編譯--位元組碼操作--javassist類庫
一、位元組碼操作
1.Java動態性的兩種常見實現方式:
- 位元組碼操作
- 反射
2.執行時操作位元組碼可以實現如下功能:
- 動態生成新的類
- 動態改變某個類的結構(新增/刪除/修改 新的屬性/方法)
3.優勢:
- 比反射開銷小,效能高
- Javaasist效能高於反射,低於ASM
二、常見的位元組碼操作類庫
1.BCEL
Byte Code Engineering Library(BCEL),這是Apache Software Foundation的Jakarta專案的一部分。BCEL是Java classworking 廣泛使用的一種框架,它可以讓您深入jvm組合語言進行類庫操作的細節。BCEL與javassist有不同的處理位元組碼方法,BCEL在實際的jvm指令層次上進行操作(BCEL擁有豐富的jvm指令集支援) 而javassist所強調的是原始碼級別的工作。2.ASM
高效能,高質量
3.CGLB(code generation library)
生成類庫,基於ASM實現4.javassist
是一個開源的分析,編輯和建立Java位元組碼的類庫。效能較ASM差,跟cglib差不多,但是使用簡單。很多開源框架都在使用它。主頁: http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
三、javassist庫的API詳解
- javassist的最外層的API和java的反射包中的API及其類似
- 它主要有CtClass, CtMethod,CtField幾個類組成,用於執行和JDK反射API中java.lang.Class, java.lang,reflect.Method,java.lang.reflect.Method.Field相同的操作
(1):建立一個類
程式碼:
public class JavassistTest { public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("bean.User"); //建立屬性 CtField field01 = CtField.make("private int id;",cc); CtField field02 = CtField.make("private String name;", cc); cc.addField(field01); cc.addField(field02); //建立方法 CtMethod method01 = CtMethod.make("public String getName(){return name;}", cc); CtMethod method02 = CtMethod.make("public void setName(String name){this.name = name;}", cc); cc.addMethod(method01); cc.addMethod(method02); //新增有參構造器 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); //無參構造器 CtConstructor cons = new CtConstructor(null,cc); cons.setBody("{}"); cc.addConstructor(cons); cc.writeFile("E:/workspace/TestCompiler/src"); } }
注意:無參構造器和有參構造器
(2):方法操作:
- 修改已有的方法體(插入程式碼到已有方法體)
- 新增方法
- 刪除方法
$0 $1 $2 | $0代表是this, $1代表方法引數的第一個引數,$2代表方法引數的第二個引數,以此類推,$N代表方法引數的第N個 |
$args | The type of $args is OBject[]. $args(0)對應的是$1,不是$0 |
$$ | 一個方法呼叫的深度 |
$r | 方法返回值的型別 |
$_ | 方法返回值。(修改方法體時不支援) |
addCatch() | 方法中加入try catch塊 $e代表 異常物件 |
$class | this的型別(Class)。也就是$0的型別 |
$sig | 方法引數的型別(Class)陣列,陣列的順序。 |
(3):屬性操作
(4):構造方法操作
getConstructors()(5)註解操作
public @interface Author{
String name();int year();
}
@Author(name="over",year=2012)
public class Point{int x,int y;}
CtClass cc=ClassPool.getDefault().get("Point");
Object[] all = cc.getAnnotations();
Author a =(Author)all[0];
String name = a.name();
int year = a.year();
System.out.println(name+":"+year);
四、侷限性:
- JDK5.0新語法不支援(包括泛型,列舉),不支援註解修改,但可以通過底層的javassist類來解決,具體參考:javassist,bytecode.annotation
- 不支援陣列的初始化,如String[]{"a","b"},除非只有陣列的容量為1
- 不支援內部類和匿名類
- 不支援continue和break 表示式
- 對於繼承關係,有些不支援 。例如
class A{}
class B extends A{}
Class C extends B{}
查資料: javassist與反射的效能比較
Demo:
public class Demo01 {
//獲取類的簡單資訊
public static void test01() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User");
//得到位元組碼
byte[] bytes = cc.toBytecode();
System.out.println(Arrays.toString(bytes));
System.out.println(cc.getName());//獲取類名
System.out.println(cc.getSimpleName());//獲取簡要類名
System.out.println(cc.getSuperclass());//獲取父類
System.out.println(cc.getInterfaces());//獲取介面
System.out.println(cc.getMethods());//獲取
}
//新生成一個方法
public static void test02() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User");
//第一種
//CtMethod cm = CtMethod.make("public String getName(){return name;}", cc);
//第二種
//引數:返回值型別,方法名,引數,物件
CtMethod cm = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);
cm.setModifiers(Modifier.PUBLIC);//訪問範圍
cm.setBody("{return $1+$2;}");
//cc.removeMethod(m) 刪除一個方法
cc.addMethod(cm);
//通過反射呼叫方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();//通過呼叫無參構造器,生成新的物件
Method m = clazz.getDeclaredMethod("add", int.class,int.class);
Object result = m.invoke(obj, 2,3);
System.out.println(result);
}
//修改已有的方法
public static void test03() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User");
CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")});
cm.insertBefore("System.out.println(\"呼叫前\");");//呼叫前
cm.insertAt(29, "System.out.println(\"29\");");//行號
cm.insertAfter("System.out.println(\"呼叫後\");");//呼叫後
//通過反射呼叫方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method m = clazz.getDeclaredMethod("hello", String.class);
Object result = m.invoke(obj, "張三");
System.out.println(result);
}
//修改已有屬性
public static void test04() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User");
//屬性
CtField cf = new CtField(CtClass.intType,"age",cc);
cf.setModifiers(Modifier.PRIVATE);
cc.addField(cf);
//增加響應的get set方法
cc.addMethod(CtNewMethod.getter("getAge",cf));
cc.addMethod(CtNewMethod.setter("setAge",cf));
//訪問屬性
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("age");
System.out.println(field);
Method m = clazz.getDeclaredMethod("setAge", int.class);
m.invoke(obj, 16);
Method m2 = clazz.getDeclaredMethod("getAge", null);
Object resutl = m2.invoke(obj,null);
System.out.println(resutl);
}
//操作構造方法
public static void test05() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User");
CtConstructor[] cons = cc.getConstructors();
for(CtConstructor con:cons){
System.out.println(con);
}
}
public static void main(String[] args) throws Exception {
//test01();
//test02();
//test03();
//test04();
test05();
}
}
相關推薦
Java學習之動態編譯--位元組碼操作--javassist類庫
一、位元組碼操作 1.Java動態性的兩種常見實現方式: 位元組碼操作反射 2.執行時操作位元組碼可以實現如下功能: 動態生成新的類動態改變某個類的結構(新增/刪除/修改 新的屬性/方法) 3.優勢: 比反射開銷小,效能高Javaasist效能高於反射,低於ASM 二、常見
2018年10月31日Java學習之常用的命令列操作
1.常用的命令列操作 win+r調出並輸入cmd. 進入D盤:D:回車進入D盤:D:回車 D盤下的目錄DIR回車 建立目錄md 2018年10月31日 那麼建立了一個2018年10月31日的目錄(目前還在d盤目錄) 進入2018年10月31日的目錄 cd
【1.1】Eigen C++ 矩陣開源庫學習之稠密矩陣和陣列操作——矩陣類
稠密矩陣和陣列操作 http://eigen.tuxfamily.org/dox-devel/group__DenseMatrixManipulation__chapter.html 包含模組: 1.矩陣類 2.矩陣和向量的運算
8.5(java學習筆記)8.5 位元組碼操作(javassist)
一、javassist javassist讓我們操作位元組碼更加簡單,它是一個類庫,允許我們修改位元組碼。它允許java程式動態的建立、修改類。 javassist提供了兩個層次的API,基於原始碼級別的和位元組碼級別的。 二、javassist建立類 1.獲取類池
Android中使用Java開源庫Javassist動態建立位元組碼的學習研究
研究該內容想要達到的目的: 通過Javassist動態建立位元組碼特性在Android專案中執行時生成.dex檔案供Android程式呼叫。 Javassist簡介: Javassist是一個開源的分析、編輯和建立Java位元組碼的類庫。它是針對JAV
java學習之路--繼承(多態的動態綁定)
程序 有一個 完全 報錯 參數類型 其中 完全匹配 一個 執行過程 動態綁定過程中,對象調用對象方的執行過程 1:編譯器查看對象的聲明類型和方法名。有可能有多個方法名相同,但參數類型不一樣的重載方法。 2:編譯器查看調用方法時提供的參數類型。該過程叫重載解析,在相同
java反射之動態代理學習筆記
ace ins 功能 運行 invoke -- ram lang glib 動態代理概述:代理:本來自己做的事情,請別人來做,被請的人就是代理對象;舉例:春節回家買票讓人代理買動態代理:在程序運行過程中產生的這個對象,而程序運行過程中產生對象其實就是我們剛才反射講解的內容,
21 Java學習之位元組流(InputStream和OutPutStream)
一.流的分類 1、從功能上:輸入流、輸出流 2、從結構上:位元組流、字元流 3、從來源上:節點流、過濾流 其中InputStream/OutputStream是為位元組流而設計的,Reader/Writer是為字元流而設計的。處理位元組或者二進位制物件使用位元組
java學習之代理(2):靜態代理和動態代理
一,代理的概念 代理是一個物件,代理物件為其他物件提供一種代理,以控制對這個物件的訪問,代理物件起到中介作用,可以去掉或者增加額外的服務。 如:火車票代售點就是火車站售票處的一個代理物件,可通過訪問代售點進行業務處理。 二,靜態代理的2種實現方式:繼承和聚合 靜態代理中的代
java的動態性------Java位元組碼操作
常見的位元組碼操作類庫BECL :是java classing廣泛使用的一種框架,可以深入理解JVM組合語言,難學,需要一些JVM底層指令ASM :輕量級的java位元組碼操作框架,直接涉及JVM底層操作和指令CGLIB :是基於ASM的的實現,強大效能高Javassist
深入理解Java虛擬機器之虛擬機器位元組碼執行引擎
執行引擎是java虛擬機器最核心的組成部分之一。 物理機的執行引擎是建立在處理器、硬體、指令集和作業系統層面上的,而虛擬機器的執行引擎是由自己實現的,可以自行制定指令集與執行引擎的結構體系,並且能夠執行那些硬體不直接支援的指令集格式。 執行引擎在執行Java
位元組碼操作_javassist庫_動態建立新類_屬性_方法_構造器_API詳解JAVA216-217
來源:http://www.bjsxt.com/ 一、S02E216_01位元組碼操作_javassist庫、介紹、動態建立新類、屬性、方法、構造器 位元組碼操作 常見的位元組碼操作類庫 JAVAssist庫 package com
java 位元組碼操作(javassist)
用javassist生成一個類(位元組碼檔案) /** * 使用javassist生成一個新的類 * @author L J */ public class JavassistDemo { public static void main(Stri
JAVA獲得版本號以及位元組碼編譯版本
公司的開發環境比較老,尋找一些jar包的時候總是會糾結對應的編譯版本,感覺很麻煩,所以寫了一個工具類用於讀取class或jar檔案的編譯版本,供大家參考。 package com.jinggujin.util; import java.io.DataIn
JAVA虛擬機器學習總結——虛擬機器位元組碼執行引擎
執行時的棧幀結構 棧幀是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧的棧元素。 棧幀儲存了方法的區域性變量表,運算元棧,動態連線和方法返回值等資訊每一個方法從呼叫至執行完成的過程,都對應者棧幀在虛擬機器棧裡面從入找
Java位元組碼操作類庫Javassist概述
Javassist(Java Programming Assistant)是一款編輯Java位元組碼的類庫。能夠在執行時定義新的Java類,在JVM載入類檔案時修改類的定義。 Javassist類庫提
Java位元組碼詳解系列之二--解析位元組碼
1、javap檢視位元組碼內容上文介紹了位元組碼的結構,本文主要通過一個簡單的例子說明class位元組碼的每一個欄位。package com.zcm.test; import java.io.Serializable; public class SourceTest im
Java學習之jdk與cglib動態代理
宣告:參考部分部落格做記錄 1.jdk動態代理實現 介面: public interface UserService { String getName(); } 介面實現: public class UserServiceImpl impl
JAVA 位元組碼操作利器javassist
1、簡介 javassist是一個開源的分析、編輯和建立java位元組碼的類庫。不需要了解虛擬機器指令,就能動態生成類或者改變類的結構。 2、下載 (2)使用的版本是javassist-3.18.0-GA。 Javassist是一個執行位元組碼操作的強而有力
關於360外掛化Replugin Activity動態修改父類的位元組碼操作
開發十年,就只剩下這套架構體系了! >>>