Java知识点总结(动态字节码操作-Javassist的API使用)

慕容烈
• 阅读 3701

Java知识点总结(动态字节码操作-Javassist的API使用)

@(Java知识点总结)[Java, 动态字节码操作]

参考文章: 传送

操作示例:

public @interface Author {
  String name();
  int year();
}
@Author(name = "gs",year=2015)
public class Emp {
  private int num;
  private String name;
  
  public Emp() {
  }
  
  public Emp(int num, String name) {
   this();
   this.num = num;
   this.name = name;
  }
  
  public void sayHello(String name){
   System.out.print("你好,");
  }
  public int getNum() {
   return num;
  }
  public void setNum(int num) {
   this.num = num;
  }
  public String getName() {
   return name;
  }
  public void setName(String name) {
   this.name = name;
  }
  
}

 
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
 
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;
 
/**
 * 测试 javassist 的 API
 *
 * @author Administrator
 *
 */
public class Test11 {
 
  // 通过类名加载已有的类
  public static void test1(ClassPool pool, CtClass cc) {
 
    try {
     cc = pool.get("com.gs.Emp");
 
     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()); // 获取接口
     
    } catch (Exception e) {
     e.printStackTrace();
    }
 
  }
 
  // 动态生成一个方法,并调用
  public static void test2(ClassPool pool, CtClass cc) {
 
    try {
     /*当CtClass对象通过writeFile()、toClass()、toBytecode()转化为Class后,
      * Javassist冻结了CtClass对象,因此,JVM不允许再次加载Class文件,所以不允许对其修改。
     因此,若想对CtClass对象进行修改,必须对其进行解冻,通过defrost()方法进行*/
     cc.defrost();
     // 生成一个方法
     CtMethod add = CtNewMethod.make("public int add(int a,int b){return $1+$2;}", cc);
     // 生成一个方法
     CtMethod subtraction = new CtMethod(CtClass.intType, "subtraction",
         new CtClass[] { CtClass.intType, CtClass.intType }, cc);
     subtraction.setModifiers(Modifier.PUBLIC);
     subtraction.setBody("return $1-$2;");
 
     cc.addMethod(add);
     cc.addMethod(subtraction);
 
     // 通过反射调用生成的方法
     Class clazz = cc.toClass();
     Emp emp = (Emp) clazz.newInstance();
     // Method method = clazz.getDeclaredMethod("add", new
     // Class[]{int.class,int.class});
     Method method = clazz.getDeclaredMethod("subtraction", new Class[] { int.class, int.class });
     Object result = method.invoke(emp, 200, 300);
     System.out.println(result);
    } catch (Exception e) {
    }
  }
 
  // 方法体前面和后面加执行语句
  public static void test3(ClassPool pool, CtClass cc) {
 
    try {
     cc.defrost();
     CtMethod m1 = cc.getDeclaredMethod("sayHello", new CtClass[] { pool.get("java.lang.String") });
     m1.insertBefore("System.out.println(\"方法体前面\");");
     m1.insertAfter("System.out.println($1);");
 
     // 通过反射调用生成的方法
     Class clazz = cc.toClass();
     Emp emp = (Emp) clazz.newInstance();
     Method method = clazz.getDeclaredMethod("sayHello", new Class[] { String.class });
     method.invoke(emp, "张三");
 
    } catch (Exception e) {
     e.printStackTrace();
    }
 
  }
 
  // 生成属性和方法
  public static void test4(ClassPool pool, CtClass cc) {
    try {
     // CtField.make("private double salary;", cc);
     CtField field = new CtField(CtClass.doubleType, "salary", cc);
     field.setModifiers(Modifier.PRIVATE);
     cc.addField(field);
 
     // cc.getDeclaredField("salary"); //获取属性
 
     CtMethod method = CtNewMethod.getter("getSalary", field);
     cc.addMethod(method);
 
     CtMethod method2 = CtNewMethod.getter("setSalary", field);
     cc.addMethod(method2);
    } catch (Exception e) {
     e.printStackTrace();
    }
 
  }
 
  // 生成构造器
  public static void test5(ClassPool pool, CtClass cc) {
 
    try {
     cc.defrost();
     CtConstructor[] cs = cc.getConstructors();
     for (CtConstructor c : cs) {
       System.out.println(c.getLongName());
       c.insertAfter("System.out.println(\"可以在构造器前后加代码\");");
     }
    } catch (Exception e) {
     e.printStackTrace();
    }
 
  }
 
  // 注解操作
  public static void test6(ClassPool pool, CtClass cc) {
    try {
     cc.defrost();
     Object[] annotations = cc.getAnnotations();
     Author author = (Author) annotations[0];
     System.out.println("name:" + author.name() + ",year:" + author.year());
 
    } catch (Exception e) {
     e.printStackTrace();
    }
  }
 
  public static void main(String[] args) {
    ClassPool pool = ClassPool.getDefault();
    CtClass cc = null;
    try {
     cc = pool.get("com.gs.Emp");
    } catch (NotFoundException e) {
     e.printStackTrace();
    }
 
    test1(pool, cc);
    //test2(pool, cc);
    test3(pool, cc);
    test5(pool, cc);
    test6(pool, cc);
  }
}
点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
3年前
java 反射
一、java的动态性反射机制动态编译动态执行JavaScript代码动态字节码操作二、动态语言动态语言   程序运行时,可以改变程序结构或变量类型,典型的语言:python、ruby、javascript等C,C,JAVA不是动态语言,java可以称之为“准动态性语言”。但java
Wesley13 Wesley13
3年前
java字节码操作
你知道如何操作JAVA字节码文件吗,这里将介绍与操作Java字节码有关的基本知识和操作Java字节码的方法及Demo,首先我们来看一下AOP的概念,AOP是OOP的延续,是AspectOrientedProgramming的缩写,意思是面向方面编程。如何操作JAVA字节码文件  本文将介绍与操作Java字节码有关的基本知识和操作Ja
Stella981 Stella981
3年前
Python Challenge Level 18
初学Python,挑战一下流行的PythonChallenge,很不幸,卡在了18关~~被字符字节码之间的转换搞得焦头烂额,不过终于搞定了还是很happy的~~~主要的问题就是16进制形式的字符如何转成字节码(注意:不是encoding)如:\'89','50','4e','47','0d','0a','1a','0a','00
Stella981 Stella981
3年前
JVM 字节码指令表
字节码助记符指令含义0x00nop什么都不做0x01aconst\_null将null推送至栈顶0x02iconst\_m1将int型1推送至栈顶0x03iconst\_0将int型0推送至栈顶0x04iconst\_1将int型1推送至栈顶0x05ic
Wesley13 Wesley13
3年前
Java虚拟机(一):JVM简介
JVM简介Java虚拟机(JVM)是由Java虚拟机规范定义的,其上运行的是字节码指令集。这种字节码指令集包含一个字节的操作码(opcode),零至多个操作数(oprand),虚拟机规范明确定义了每种字节码指令完成的功能是什么以及需要多少个操作数。Java虚拟机上运行的class文件,这个文件中包含字节码指令流以及类定义的信息,所以Java虚
Wesley13 Wesley13
3年前
Java字节码增强探秘
1.字节码1.1什么是字节码?Java之所以可以“一次编译,到处运行”,一是因为JVM针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看出字节码对于Java生态的重要性。之所以被称之为字节码,是因为字节码文件由十六进制值组成,
Wesley13 Wesley13
3年前
Javassist简介
Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的ShigeruChiba(千叶滋)所创建的。它已加入了开放源代码JBoss应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。它可以用来检查、”动态”修改以及创建Java类。其功能与jdk自带的反射功能类
Wesley13 Wesley13
3年前
JAVA字节码执行引擎总结
字节码指令大部分操作指令都有对应不同类型的不同指令,比如iloadistoreireturn表示加载(整形变量进操作数栈)、定义一个整形局部变量、返回一个int类型值return11》iconst2;ireturn编译期优化:直接将11定义为常量2运行时就不用再做计算了这段代码操作数栈的最大深度是2
Stella981 Stella981
3年前
JVM基础命令
介绍java虚拟机的指令功能,至少能阅读java代码生成的字节码指令含义一、概述Java虚拟机采用基于栈的架构,其指令由操作码和操作数组成。操作码:一个字节长度(0~255),意味着指令集的操作码个数不能操作256条。操作数:一条指令可以有零或者多个操作数,且操作数可以是1个或者多个字节。编译后的代码没有采用操作数
打开java语言世界通往字节码世界的大门——ASM字节码操作类库
一、ASM介绍1、ASM是什么ASM是一个通用的Java字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从中构建定制的复杂转换和代码分析工具。ASM提供了与其他Java字节码框架类似的
慕容烈
慕容烈
Lv1
短暂的总是浪漫,漫长总会不满。
文章
5
粉丝
0
获赞
0