[Java]Javassist基本用法
Javassist是一個能夠操作位元組碼框架,在學習的過程中存在了一些問題,用部落格的方式記錄下來,希望對大家有所幫助。
一、例項功能
學習的例項來自於 IBM developer 主要功能實現計算一個方式具體的執行時間.
二、程式碼例項
- package org.java.javassist.one;
- /**
- * 該類並不是對StringBuilder進行解釋,而是提供了中方式,方便我們來使用javassist的一些細節
- * @author xianglj
- * @date 2016/7/13
- * @time 9:59
- */
-
publicclass StringBuilderTest {
- /**
- * 假如我們現在需要計算該程式的計算時間:
- * 則可以標記開始時間(start)和結束時間(end)
- * 最終的執行時間為(end - start)的值
- * @param length
- * @return
- */
- public String buildString(int length) {
- String result = "";
- for(int i = 0; i<length; i++ ) {
-
result += (i %26 +
- }
- return result;
- }
- publicstaticvoid main(String[] args) {
- /**
- * class.getName()返回的字串中,不僅包括了類的名稱,同時也包含了該類所在的包名稱
- * <pre>
- * 格式:
- * packagename.classname
- * </pre>
- */
-
// System.out.println(StringBuilderTest.class.getName());
- StringBuilderTest test = new StringBuilderTest();
- if(null != args) {
- for(int i = 0, len = args.length; i<len; i++) {
- String result = test.buildString(Integer.parseInt(args[i]));
- System.out.println("result:" + result);
- }
- }
- }
- }
三、解決方案
1) 第一個中解決方案,也是最直觀的方式,就是在進入方法時,記錄一個當前時間 start , 當代碼執行完成之後,獲取當前時間 end , 然後採用 (end - start)的方式,來獲取程式碼執行時間
2) 第二中方式,我們採用Javassit框架來實現:
(1) 使用通過ClassPool 來獲取 CtClass物件
(2) 從CtClass物件中,獲取buildString()的方法
(3) 為buildString()方法新增程式碼塊
特別說明:
為方法新增程式碼塊,有三種方式可以實現
- * <pre>
- * 1. 新增的程式碼不能引用在方法中其他地方定義的區域性變數。這種限制使我不能在 Javassist 中使用在原始碼中使用的同樣方法實現計時程式碼,
- * 在這種情況下,我在開始時新增的程式碼中定義了一個新的區域性變數,並在結束處新增的程式碼中引用這個變數。
- *
- * 2. 我 可以在類中新增一個新的成員欄位,並使用這個欄位而不是區域性變數。不過,這是一種糟糕的解決方案,
- * 在一般性的使用中有一些限制。例如,考慮在一個遞迴方法中會發生的事情。每次方法呼叫自身時,上次儲存的開始時間值就會被覆蓋並且丟失。
- *
- * 3. 我可以保持原來方法的程式碼不變,只改變方法名,然後用原來的方法名增加一個新方法。
- * </pre>
程式碼如下:
- package org.java.javassist.one;
- import javassist.*;
- import java.io.IOException;
- /**
- * 通過Javassist來為需要實現計算的方法前後各加上一個攔截器,
- * 依次來實現方法計算的時間
- * <pre>
- * 1. 新增的程式碼不能引用在方法中其他地方定義的區域性變數。這種限制使我不能在 Javassist 中使用在原始碼中使用的同樣方法實現計時程式碼,
- * 在這種情況下,我在開始時新增的程式碼中定義了一個新的區域性變數,並在結束處新增的程式碼中引用這個變數。
- *
- * 2. 我 可以在類中新增一個新的成員欄位,並使用這個欄位而不是區域性變數。不過,這是一種糟糕的解決方案,
- * 在一般性的使用中有一些限制。例如,考慮在一個遞迴方法中會發生的事情。每次方法呼叫自身時,上次儲存的開始時間值就會被覆蓋並且丟失。
- *
- * 3. 我可以保持原來方法的程式碼不變,只改變方法名,然後用原來的方法名增加一個新方法。
- * </pre>
- * @author xianglj
- * @date 2016/7/13
- * @time 10:07
- */
- publicclass JavassistTiming {
- publicstaticvoid main(String[] args) {
- //開始獲取class的檔案
- javassist();
- }
- publicstaticvoid javassist() {
- //開始獲取class的檔案
- try {
- // String classFileName = StringBuilderTest.class.getName();
- String classFileName = "org.java.javassist.one.StringBuilderTest";
- CtClass ctClass = ClassPool.getDefault().getCtClass(classFileName);
- if(ctClass == null) {
- System.out.println("Class File (" + classFileName + ") Not Found.....");
- } else {
- addTiming(ctClass, "buildString");
- //為class新增計算時間的過濾器
- ctClass.writeFile();
- }
- Class<?> clazz = ctClass.toClass();
- StringBuilderTest test = (StringBuilderTest) clazz.newInstance();
- test.buildString(2000);
- } catch (NotFoundException e) { //類檔案沒有找到
- e.printStackTrace();
- } catch (CannotCompileException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- /**
- * 為方法新增攔截器:
- * <pre>
- * 構造攔截器方法的正文時使用一個 java.lang.StringBuffer 來累積正文文字(這顯示了處理 String 的構造的正確方法,
- * 與在 StringBuilder 的構造中使用的方法是相對的)。這種變化取決於原來的方法是否有返回值。
- * 如果它 有返回值,那麼構造的程式碼就將這個值儲存在區域性變數中,這樣在攔截器方法結束時就可以返回它。
- * 如果原來的方法型別為 void ,那麼就什麼也不需要儲存,也不用在攔截器方法中返回任何內容。
- * </pre>
- * @param clazz 方法所屬的類
- * @param method 方法名稱
- */
- privatestaticvoid addTiming(CtClass clazz, String method) throws NotFoundException, CannotCompileException {
- //獲取方法資訊,如果方法不存在,則丟擲異常
- CtMethod ctMethod = clazz.getDeclaredMethod(method);
- //將舊的方法名稱進行重新命名,並生成一個方法的副本,該副本方法採用了過濾器的方式
- String nname = method + "$impl";
- ctMethod.setName(nname);
- CtMethod newCtMethod = CtNewMethod.copy(ctMethod, method, clazz, null);
- /*
- * 為該方法新增時間過濾器,用來計算時間。
- * 這就需要我們去判斷獲取時間的方法是否具有返回值
- */
- String type = ctMethod.getReturnType().getName();
- StringBuffer body = new StringBuffer();
- body.append("{\n long start = System.currentTimeMillis();\n");
- if(!"void".equals(type)) {
- body.append(type + " result = ");
- }
- //可以通過$$將傳遞給攔截器的引數,傳遞給原來的方法
- body.append(nname + "($$);\n");
- // finish body text generation with call to print the timing
- // information, and return saved value (if not void)
-
body.append("System.out.println(\"Call to method " + nname + " took \" + \n (System.currentTimeMillis()-start) + " + "\" ms.\");\n"
相關推薦
[Java]Javassist基本用法
Javassist是一個能夠操作位元組碼框架,在學習的過程中存在了一些問題,用部落格的方式記錄下來,希望對大家有所幫助。 一、例項功能 學習的例項來自於 IBM developer 主要功能實現計算一個方式具體的執行時間. 二、程式碼例項 p
java基礎:運算符的基本用法
自增 另一個 stat 不同 兩個 流程 ava -- 個數 運算符: 就是對常量和變量進行操作的符號。 算數運算符: A:+,-,*,/,%,++,-- B:+的用法 a:加法 b:正號 c:字符串連接符 C:/和%的區別 數據做除法操作的時候,/取得是商
《Java從入門到放棄》入門篇:springMVC基本用法
java springmvc springMVC可以理解成用來做數據顯示處理的框架,主要內容就是控制器和視圖的處理。在已經安裝了spring框架的基礎上繼續下面的步驟(我使用的MyEclipse2014)。 1. 修改web.xml文件 2. 在WEB-INF目錄創建springmvc的配
java中正則表達式基本用法(轉)
code ack acea print 表達式 劃線 跟著 以及 n) https://www.cnblogs.com/xhj123/p/6032683.html 正則表達式是一種可以用於模式匹配和替換的規範,一個正則表達式就是由普通的字符(例如字符a到z)以及特殊字符(元
JAVA--properties的基本用法
java中的properties檔案是一種配置檔案,主要用於表達配置資訊,檔案型別為*.properties,格式為文字檔案,檔案的內容是格式是"鍵=值"的格式,在properties檔案中,可以用"#"來作註釋,properties檔案在Java程式設計中用到的地方很多,操作很方便。一、prope
java註解之編譯時註解RetentionPolicy.CLASS 基本用法
1 前言 我們知道,在日常開發中我們常用的兩種註解是執行時註解和編譯時註解,執行時註解是通過反射來實現註解處理器的,對效能稍微有一點損耗,而編譯時註解是在程式編譯期間生成相應的代理類,替我們完成某些功能。今天我們來講解一下編譯時註解以及寫一個小例子,以便加深對編譯時註解的理解。
Java String類的基本用法
一、String類物件的建立 字串宣告:String stringName; 字串建立:stringName = new String(字串常量);或stringName = 字串常量; 二、String類構造方法 1、public String() 無參構造方法,用來建立空字串的Strin
知識困惑丨java中return的基本用法
今天做一個題,在語句中使用了return,怎麼都得不到自己想要的結果,後來,把return去掉,換了輸出語句,所以就瞭解下return的用法; 第一個用法:方法中定義了資料型別,則必須要有一個返回值用return; public int Return() { return 0;
Java BufferedImage的基本用法
1:讀取本地圖片: File file = new File(”001.jpg“);//本地圖片 BufferedImage image=(
Java string的基本用法
一,定義字串與子串 定義 String e ="";\空字串 String E=“Hello”; 提取子串使用Substring方法: String E=“Hello”; String s=E.substring(0,4);\s等於Hell System.out.println(s)
Java string特點及基本用法
開始學習Java之後,便會接觸到string類。string就像是C語言中常說的字串,字串其實就是一個String類的物件。 在這裡我們簡單介紹一下string類的用法特點,並且結合程式碼演示。 1、定義字串 第一步我們先定義一下字串。字串的定義一般有兩種方法,
Java中的getGenericSuperclass方法的基本用法
通過getGenericSuperclass方法可以獲取當前物件的直接超類的 Type package cn.tzz.lang.clazz; public class User { privat
java 執行緒池基本用法
1,執行緒與程序的基本區別 ->程序: 擁有自己一整套變數,資料之間不可見。建立/撤銷-開銷很大。 ->執行緒: 共享資料,共享變數儲存在主存中(Main Memory),每個現場有自己私有的本地記憶體(Local Memory),本地記憶體存的是主存的一個副本,與程
Java產生隨機數用法及基本用法(轉)
1.隨機產生四位數[1000,9999] num=(int)(Math.random()*9000)+1000; Math.random()方法是產生double型[0,1)的資料,[0,1)*9000=[1,9001),用int型別強轉後便是[0,8999], 因而可以得到1000~9
java中ArrayList用法詳解,基本用法(含增刪改查)
1、什麼是ArrayList ArrayList就是動態陣列,它提供了①動態的增加和減少元素 ②實現了ICollection和IList介面 ③靈活的設定陣列的大小ArrayList是一個其容量能夠動態增長的動態陣列。它繼承了AbstractList,實現了List、Rand
JAVA中Set的基本用法
首先我們來介紹常見的Set型別:HashSet它有幾個特性,首先它不會出現重複的元素,其次它是無序的,此外它可以含有空元素。下面我們看示例:package lab1;import java.util.HashSet;import java.util.Iterator;im
JDBC(Java Data Base Connectivity)基本用法
一、什麼是JDBC JDBC(Java Database Connection)為java開發者使用資料庫提供了統一的程式設計介面,它由一組java類和介面組成.是java程式與資料庫系統通訊的標準A
Java學習筆記之LinkedList基本用法
LinkedList簡介LinkedList 是一個繼承於AbstractSequentialList的雙向連結串列。它也可以被當作堆疊、佇列或雙端佇列進行操作。LinkedList 實現 List 介面,能進行佇列操作。LinkedList 實現 Deque 介面,即能將L
java中的string類的基本用法
內容:介紹String類如何判斷是否相等,字串的子串,如何連線字串等等,並給出相應的程式碼。(要求:不少於1000字,Java程式碼不少於100行。) ①string類如何判斷是否相等 ava中的是用來判斷物件所使用的記憶體地址是不是同一個,進而判斷是不是同一個
作業2 Java String類的基本用法
字串型別屬於引用資料型別,Java中用String表示字串型別。 string是final所修飾的。代表著string這個類不能有子類。(也就是指類中對字串操作的功能是不能被我們複寫)String類物件建立後不能修改,由0或多個字元組成,包含在一對雙引號之間。