中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java動態字節技術之Javassist

發布時間:2020-08-19 08:38:19 來源:ITPUB博客 閱讀:268 作者:前端程序猿 欄目:web開發

概述

Javassist是一個開源的分析、編輯和創建Java字節碼的類庫,可以直接編輯和生成Java生成的字節碼。相對于bcel, asm等這些工具,開發者不需要了解虛擬機指令,就能動態改變類的結構,或者動態生成類。javassist簡單易用, 快速。

重要的類

1. ClassPool:javassist的類池,使用ClassPool 類可以跟蹤和控制所操作的類,它的工作方式與 JVM 類裝載器非常相似

2. CtClass: CtClass提供了類的操作,如在類中動態添加新字段、方法和構造函數、以及改變類、父類和接口的方法。

3. CtField:類的屬性,通過它可以給類創建新的屬性,還可以修改已有的屬性的類型,訪問修飾符等

4. CtMethod:類中的方法,通過它可以給類創建新的方法,還可以修改返回類型,訪問修飾符等, 甚至還可以修改方法體內容代碼

5. CtConstructor:與CtMethod類似

在這里小編建了一個前端學習交流扣扣群:132667127,我自己整理的最新的前端資料和高級開發教程,如果有想需要的,可以加群一起學習交流

API運用

ClassPool

1	// 類庫, jvm中所加載的class

2 ClassPool pool = ClassPool.getDefault();
3 // 加載一個已知的類, 注:參數必須為全量類名
4 CtClass ctClass = pool.get("com.itheima.Student");
5 // 創建一個新的類, 類名必須為全量類名
6 CtClass tClass = pool.makeClass("com.itheima.Calculator");

CtField

1	// 獲取已知類的屬性

2 CtField ctField = ctClass.getDeclaredField("name");
3 // 構建新的類的成員變量
4 CtField ctFieldNew = new CtField(CtClass.intType,"age",ctClass);
5 // 設置類的訪問修飾符為public
6 ctFieldNew.setModifiers(Modifier.PUBLIC);
7 // 將屬性添加到類中
8 ctClass.addField(ctFieldNew);

CtMethod

1	// 獲取已有方法

4 //創建新的方法, 參數1:方法的返回類型,參數2:名稱,參數3:方法的參數,參數4:方法所屬的類
5 CtMethod ctMethod = new CtMethod(CtClass.intType, "calc", new CtClass[]
{CtClass.intType,CtClass.intType}, tClass);
6 // 設置方法的訪問修飾
7 ctMethod.setModifiers(Modifier.PUBLIC);
8 // 將新建的方法添加到類中
9 ctClass.addMethod(ctMethod);
10 // 方法體內容代碼 $1代表第一個參數,$2代表第二個參數
11 ctMethod.setBody("return $1 + $2;");

2 CtMethod ctMethod = ctClass.getDeclaredMethod("sayHello");

CtConstructor

// 獲取已有的構造方法, 參數為構建方法的參數類型數組

CtConstructor ctConstructor = ctClass.getDeclaredConstructor(new CtClass[]{});
// 創建新的構造方法
CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType},ctClass); ctConstructor.setModifiers(Modifier.PUBLIC);
ctConstructor.setBody("this.age = $1;");
ctClass.addConstructor(ctConstructor);
// 也可直接創建
ctConstructor = CtNewConstructor.make("public Student(int age){this.age=age;}", ctClass);

案例

1.  創建maven工程并添加依賴

Java動態字節技術之Javassist

添加依賴

Java動態字節技術之Javassist

添加Student類

package com.itheima;

public class Student {
private int age; private String name;
public int getAge() { return age;
}
public void setAge(int age) { this.age = age;
}
public String getName() { return name;
}
public void setName(String name) { this.name = name;
}
public void sayHello(){
System.out.println("Hello, My name is " + this.name);
}
}

2.  修改已有方法體,插入新的代碼

對已有的student類中的sayHello方法,當調用時,控制臺會輸出: Hello, My name is 張三(name=張三)

需求:通過動態修改sayHello方法,當調用sayHello時,除了輸出已經的內容外,再輸出當前學生的age信息 創建JavassistDemo測試類,代碼實現如下:

package com.itheima.test; import org.junit.Test; import com.itheima.Student;

import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod;

@SuppressWarnings("unchecked") public class JavassistDemo {

@Test
public void t1() throws Exception{
// 類庫池, jvm中所加載的class
ClassPool pool = ClassPool.getDefault();
// 獲取指定的Student類
CtClass ctClass = pool.get("com.itheima.Student");
// 獲取sayHello方法
CtMethod ctMethod = ctClass.getDeclaredMethod("sayHello");
// 在方法的代碼后追加 一段代碼
ctMethod.insertAfter("System.out.println(\"I'm \" + this.age + \" years old.\");");
// 使用當前的ClassLoader加載被修改后的類
Class<Student> newClass = ctClass.toClass();

Student stu = newClass.newInstance();
stu.setName("張三");
stu.setAge(18);

stu.sayHello();
}
}

運行結果:

Java動態字節技術之Javassist

3.  動態添加方法

接下來我們給Student類添加一個計算的方法,但不是直接在Student類中添加,而是使用javassist,動態添加

1	public int calculate(int a, int b){

2 return a+b;
3 }
創建測試方法t2,代碼如下

1 @Test
2 public void t2() throws Exception{
3 // 類庫池, jvm中所加載的class
4 ClassPool pool = ClassPool.getDefault();
5 // 獲取指定的Student類
6 CtClass ctClass = pool.get("com.itheima.Student");
7 // 創建calc方法, 帶兩個參數,參數的類型都為int類型
8 CtMethod ctMethod = new CtMethod(CtClass.intType,"calc",
9 new CtClass[]{CtClass.intType,CtClass.intType}, ctClass);
10 // 設置方法的訪問修飾
11 ctMethod.setModifiers(Modifier.PUBLIC);
12 // 設置方法體代碼
13 ctMethod.setBody("return $1 + $2;");
14 // 添加新建的方法到原有的類中
15 ctClass.addMethod(ctMethod);
16 // 加載修改后的類
17 ctClass.toClass();
18 // 創建對象
19 Student stu = new Student();
20 // 獲取calc方法
21 Method dMethod = Student.class.getDeclaredMethod("calc", new Class[]
{int.class,int.class});
22 // 反射調用 方法
23 Object result = dMethod.invoke(stu, 10,20);
24 // 打印結果
25 System.out.println(String.format("調用calc方法,傳入參數:%d,%d", 10,20));
26 System.out.println("返回結果:" + (int)result);
27 }

控制臺輸出結果:

Java動態字節技術之Javassist

4.  動態創建類

下面我們再來個神的魔術,無中生有

1 @Test

2 public void t3() throws Exception{
3 ClassPool pool = ClassPool.getDefault();
4 // 創建teacher類
5 CtClass teacherClass = pool.makeClass("com.itheima.Teacher");
6 // 設置為公有類
7 teacherClass.setModifiers(Modifier.PUBLIC);
8 // 獲取String類型
9 CtClass stringClass = pool.get("java.lang.String");
10 // 獲取list類型
11 CtClass listClass = pool.get("java.util.List");
12 // 獲取學生的類型
13 CtClass studentClass = pool.get("com.itheima.Student");
14 // 給teacher添加name屬性
15 CtField nameField = new CtField(stringClass, "name", teacherClass);
16 nameField.setModifiers(Modifier.PUBLIC);
17 teacherClass.addField(nameField);
18 // 給teacher類添加students屬性
19 CtField studentList = new CtField(listClass, "students",teacherClass);
20 studentList.setModifiers(Modifier.PUBLIC);
21 teacherClass.addField(studentList); 22
23 // 給teacher類添加無參構造方法
24 CtConstructor ctConstructor = CtNewConstructor.make("public Teacher()
{this.name=\"abc\";this.students = new java.util.ArrayList();}", teacherClass);
25 teacherClass.addConstructor(ctConstructor); 26
27 // 給teacher類添加addStudent方法
28 CtMethod m = new CtMethod(CtClass.voidType, "addStudent", new CtClass[]{studentClass}, teacherClass);
29 m.setModifiers(Modifier.PUBLIC);
30 // 添加學生對象到students屬性中, $1代表參數1
31 m.setBody("this.students.add($1);");
32 teacherClass.addMethod(m); 33
34 // 給teacher類添加sayHello方法
35 m = new CtMethod(CtClass.voidType, "sayHello", new CtClass[]{}, teacherClass);
36 m.setModifiers(Modifier.PUBLIC);
37 m.setBody("System.out.println(\"Hello, My name is \" + this.name);");
38 m.insertAfter("System.out.println(\"I have \" + this.students.size() + \" students\");");
39 teacherClass.addMethod(m); 40
41 // 加載修改后的類
42 Class<?> cls = teacherClass.toClass();
43 // 實例teacher對象
44 Object obj = cls.newInstance();
45 // 獲取addStudent方法
46 Method method = cls.getDeclaredMethod("addStudent", Student.class);

運行結果:

Java動態字節技術之Javassist

總結

javassist被用于struts2和hibernate中,都用來做動態字節碼修改使用。一般開發中不會用到,但在封裝框架時比 較有用。雖然javassist提供了一套簡單易用的API,但如果用于平常的開發,會有如下幾點不好的地方:

  • 1. 所引用的類型,必須通過ClassPool獲取后才可以使用
  • 2. 代碼塊中所用到的引用類型,使用時必須寫全量類名
  • 3. 即使代碼塊內容寫錯了,它也不會像eclipse等開發工具一樣有提示,它只有在運行時才報錯
  • 4. 動態修改的類,必須在修改之前,jvm中不存在這個類的實例對象。修改方法的實現必須在修改的類加載之前進行。
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

上饶县| 临江市| 神池县| 临猗县| 靖安县| 韩城市| 会同县| 永定县| 白山市| 射洪县| 万盛区| 虎林市| 雷山县| 滨州市| 彰化县| 蓝山县| 黔西| 平江县| 高平市| 麻城市| 古交市| 宜昌市| 肥乡县| 奉贤区| 富顺县| 固原市| 慈溪市| 仪征市| 云浮市| 沁阳市| 贵港市| 获嘉县| 德清县| 西乌珠穆沁旗| 怀集县| 汉寿县| 大连市| 宜兰县| 营山县| 泰州市| 玉田县|