javassist对已有的类进行操作

article/2025/9/15 4:49:31

准备工作:

首先创建一个java项目,然后导入javassist.jar包

创建一个注解

package com.chengyu.javassist;public @interface Auto {String name();int year();
}

创建一个接口

public interface Earth {
}

创建两个类

public class Pepelo{
}

package com.chengyu.javassist;@Auto(name="KO",year=1999)
public class Student extends Pepelo implements Earth{private int age;private String name;public int myTest(int a){System.out.println("我在学习。。。。" + a);return 6666;}public Student(){}public Student(int age,String name){this.age = age;this.name = 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;}
}

Student类继承Pepelo类实现Earth接口

然后我们开始测试

首先我们来对类进行操作,获取类的信息

 /*** javassist处理类的基本操作*/public static void test01() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");byte [] bytes = cc.toBytecode(); //获取类的二进制字节码转成byte数组String allName = cc.getName();   //获取类的全限定名  com.chengyu.javassist.StudentString name = cc.getSimpleName(); //获取类的简单名   StudentCtClass superclass = cc.getSuperclass();    //获取类的父类CtClass[] interfaces = cc.getInterfaces();  //获取类的父接口System.out.println(allName);System.out.println(name);System.out.println(superclass.getName());System.out.println(interfaces[0].getName());System.out.println(Arrays.toString(bytes));}

新增一个方法

/*** 新增方法*/public static void test02() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");//CtMethod make = CtNewMethod.make("public int add(int a,int b){return a+b;}",cc);  创建方法可以使用这种方法 也可以使用下面的方法CtMethod ctMethod = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);//new CtMethod 的第一个参数为返回类型,第二个参数是方法名,第三个参数为方法的参数列表(这里没有给参数命名),第四个参数为CtClass类ctMethod.setModifiers(Modifier.PUBLIC); //声明方法的访问权限ctMethod.setBody("{return $1+$2;}");    //设置方法体 上面没有给参数命名,这里需要使用$符号进行匹配/*** $0 表示this  $1表示第一个形参   $2 表示第二个形参 以此类推* $args 表示的是一个Object[] 将参数列表放入这个数组中  args[0] 对应的就是 $1 args[1] 对应的就是$2 以此类推* $$ 所有方法参数的简写,主要用在方法调用上* $cflow 一个方法调用的深度,主要用于递归调用上* $r 方法返回值的类型* $_  方法的返回值(修改方法体时不支持)* addCatch() 方法中加入try catch块* $e 表示异常对象* $class this的类型(Class) 也就是$0的类型* $sig 方法参数的类型(Class)数组,数组的顺序为参数的顺序**/cc.addMethod(ctMethod); //将方法添加到类中//下面使用java反射来进行调用验证Class clazz = cc.toClass();Object obj = clazz.newInstance();Method declaredMethod = clazz.getDeclaredMethod("add",int.class, int.class);Object invoke = declaredMethod.invoke(obj, 200, 300);System.out.println("result:" + (int)invoke);}

执行结果

 对已有的方法进行修改

 /*** 修改已有的方法*/public static void test03() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");//根据方法名和参数列表来获取方法CtMethod myTest = cc.getDeclaredMethod("myTest", new CtClass[]{CtClass.intType});myTest.insertBefore("System.out.println($1 + \" 准备打开书\");"); //在方法前进行插入代码myTest.insertAfter("System.out.println(\"已经学完了,出去玩\");"); //在方法后面进行插入代码myTest.insertAt(16,"System.out.println(\"这是在某一行插入的代码!\");"); //在某一行插入代码//使用反射进行调用测试Class clazz = cc.toClass();Object obj = clazz.newInstance();Method declaredMethod = clazz.getDeclaredMethod("myTest",int.class);Object invoke = declaredMethod.invoke(obj, 200);System.out.println("result:" + (int)invoke);}

执行的结果

 对属性的操作-新增一个属性并且为其添加set和get方法

 /*** 新增属性并且添加set和get方法*/public static void test04() throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");//CtField make = CtField.make("private String phone;", cc);  可以通过这种方式添加属性,也可以使用下面的方式CtField ctField = new CtField(pool.get("java.lang.String"),"phone",cc);//new CtField 第一个参数为属性的类型,第二个参数为属性名,第三个参数为CtClassctField.setModifiers(Modifier.PRIVATE);  //设置属性的访问权限cc.addField(ctField);                    //将属性添加到方法中//CtField phone = cc.getDeclaredField("phone");  这里可以根据属性名来获取属性//添加set和get方法 第一个参数为方法名 第二个参数为属性cc.addMethod(CtNewMethod.getter("getPhone",ctField));cc.addMethod(CtNewMethod.setter("setPhone",ctField));//通过反射进行调用测试Class clazz = cc.toClass();Object obj = clazz.newInstance();Method setPhone = clazz.getDeclaredMethod("setPhone",String.class);Method getPhone = clazz.getDeclaredMethod("getPhone",null);setPhone.invoke(obj,"13088888888");Object phone = getPhone.invoke(obj);System.out.println(String.valueOf(phone));}

执行结果:

 对构造方法的操作

   public static void test05()throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");CtConstructor[] constructors = cc.getConstructors();for(CtConstructor c : constructors){System.out.println(c.getLongName());//打印构造方法的全类限定名c.insertBefore("System.out.println(\"我是构造方法\");"); //当然我们也可以对构造方法进行操作}Class clazz = cc.toClass();Object obj = clazz.newInstance();}

执行结果:

 对注解的操作

public static void test06()throws Exception{ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get("com.chengyu.javassist.Student");Object [] all = cc.getAnnotations();  //获取标注在类上的所有注解for(Object a : all){if(a instanceof Auto){Auto b = (Auto) a;System.out.println("name : " + b.name() + " year : " + b.year());}}}

执行结果

 在这里就做这些介绍

当然javassist也是有一定的局限性的:

1、泛型、枚举是不支持的,

2、注解的修改也不支持,虽然可以通过底层的javassist类来解决

3、不支持数组的初始化工作,除非数组的容量为1

4、不支持内部类和匿名类

5、不支持continue和break

6、对于复杂的继承也不支持,支持简单的继承关系

原创不易,不喜勿喷,有更好的建议欢迎大家留言


http://chatgpt.dhexx.cn/article/YnUPmB6e.shtml

相关文章

【Javassist】快速入门系列03 使用Javassist实现方法异常处理

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 文章目录 系列文章目录前言引入Javassist jar包使用Javassist实现方法异常处理 总结说明 前言 上一章我们介绍了使用使用Javassist实现了对方法执行时…

【Javassist】快速入门系列04 使用Javassist更改整个方法体

系列文章目录 01 在方法体的开头或结尾插入代码 02 使用Javassist实现方法执行时间统计 03 使用Javassist实现方法异常处理 04 使用Javassist更改整个方法体 文章目录 系列文章目录前言引入Javassist jar包使用Javassist更改整个方法体 总结说明 前言 上一章我们介绍了使用Ja…

Java字节码编程之非常好用的javassist

我为什么要研究这个? 因为我在开发一个框架的时候需要用到。 我开发的这个框架,有一个注解,当用户输入变量名,类名的时候,我这个框架可以为其自动生成一个对象,并加载到内存中供以后使用。 这个小功能可…

javassist学习

Java 字节码以二进制的形式存储在 .class 文件中,每一个 .class 文件包含一个 Java 类或接口。Javaassist 就是一个用来 处理 Java 字节码的类库。它可以在一个已经编译好的类中添加新的方法,或者是修改已有的方法,并且不需要对字节码方面有深…

Javassist

Javassist Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。 相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。javassist简单易用&…

[Java基础]—Javassist

Javassist Javassist (JAVA programming ASSISTant) 是在 Java 中编辑字节码的类库;它使 Java 程序能够在运行时定义一个新类, 并在 JVM 加载时修改类文件。原理与反射类似,但开销相对较低。 常用API ClassPool getDefault : 返回默认的 ClassPool 是单例模式的&…

Javassist基本用法

Javassist概述 Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件,添加新的方法,或者是修改已有的方法。Javassist使用户不必关心字节码相关的规范…

Java中的高性能字节码工具:Javassist

前言 一般常见的动态方法调用使用Reflection或者字节码生成技术。虽然JDK已对反射进行了优化但在追求性能的场景中仍然显得性能不佳。本文即是介绍一个面向程序员友好的字节码操作类库javassist。根据benchmark其展现的性能已几乎无异于直接调用。 开源地址:javas…

Java字节码技术javassist

一、Javassist入门 (一)Javassist是什么 Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。Javassist使用户不必关心字节码相关的规范也是可以编…

java--javassist学习

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的。它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jb…

javassist使用指南

目录 一、快速入门1.1 创建class文件1.2 ClassPool的相关方法1.3 CtClass的相关方法1.4 CtMethod的相关方法1.5 调用生成的类对象1.5.1 通过反射调用1.5.2 通过接口调用 1.6 修改现有的类对象 二、将类冻结三、类搜索路径四、$开头的特殊字符五、ProxyFactory的使用 我们知道Ja…

systemd介绍

由来 Linux 的启动一直采用init进程,这种方法有两个缺点。一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程,二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理…

systemd man手册

SYSTEMD(1)systemd SYSTEMD(1) 名称 systemd,init-systemd系统和服务管理器 概要 /lib/systemd/systemd [OPTIONS...]init [OPTIONS...] {COMMAND}描述 systemd是Linux操作系统的系统和服务管理器。在启动时作为PID的…

systemd wsl 测试笔记

文章目录 systemd 简介WSL systemdsystemctljournalctlhello serviceSleep 与 Timeout 测试Requires 测试After 测试 systemd 简介 Linux 从关闭到运行, 完整的启动和启动过程有三个主要部分: 硬件启动(Hardware boot): 初始化系统硬件Linux 引导(Linux boot): 加载 Linux 内核…

Linux systemd启动流程

以Ubuntu 18.04.2 LTS为例,列出Systemd启动target中涉及单元(Unit). default.target ( graphical.target by default) graphical.targetRequiresmulti-user.targetWantsdisplay-manager.serviceConflictsrescue.service rescue.targetAftermulti-user.target rescu…

关于 Linux中systemd的一些笔记

写在前面 嗯,准备RHCA,学习整理这部分知识博文内容涉及: systemd简述对于unit的信息的介绍通过systemctl命令控制Service unit的DemoService unit配置文件内容,权值的一些介绍 傍晚时分,你坐在屋檐下,看着天慢慢地黑下…

Linux-Systemd

目录 一、Systemd概述 二、Systemd优势 2.1兼容性 2.2启动速度 2.3systemd 提供按需启动能力 2.4采用 linux 的 cgroups 跟踪和管理进程的生命周期 2.5启动挂载点和自动挂载的管理 2.6实现事务性依赖关系管理 2.7日志服务 2.8 依赖关系 2.9systemd 事务 三、unit(单…

Systemd 简介

一 概述 Linux 服务管理有两种方式service和systemctl。而systemd是Linux系统最新的初始化系统(init),作用是提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动,systemd对应的进程管理命令就是systemctl。值得一提…

systemd简介

Systemd 是一个专用于 Linux 操作系统的系统与服务管理器,其目的是要取代Unix时代以来一直在使用的init系统。 systemd概述Systemd 是 Linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度。 systemd框架图 根据 Linux 惯…

Systemd 入门及常用命令

目录 Systemdsystemd架构systemd 系统管理管理系统查看启动耗时查看当前主机的信息 Unit 资源查看当前系统的所有 Unit查看系统状态和单个 Unit 的状态 Unit 管理依赖关系Unit 配置文件查看配置文件的内容 Targettarget(Systemd) 与 runlevel&#xff08…