字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》
作者:小傅哥
博客:https://bugstack.cn
沉淀、分享、成长,让自己和他人都能有所收获!
一、前言
在上一篇 Helloworld 中,我们初步尝试使用了 Javassist
字节编程的方式,来创建我们的方法体并通过反射调用运行了结果。大致了解到创建在使用字节码编程的时候基本离不开三个核心类;ClassPool
、CtClass
、CtMethod
,它们分别管理着对象容器、类和方法。但是我们还少用一样就是字段;CtFields
,在这一章节中我们不止会使用字段,还会创建多个不同入参类型和返回值的学习。
在学习之前先重点列一下相关的知识点,如下;
CtClass.doubleType
、intType
、floatType
等 8 个基本类型和一个voidType
,也就是空的返回类型。- 传递和返回的是对象类型时,那么需要时用;
pool.get(Double.class.getName()
,进行设置。 - 当需要设置多个入参时,需要在数组中以此设置入参类型;
new CtClass[]{CtClass.doubleType, CtClass.doubleType}
。 - 在方法体中需要取得入参并计算时,需要使用
$1
、$2
...,数字表示入参的位置。$0
是 this。 - 设置属性字段,并赋值
Javassist
中的装箱/拆箱
好!那么我们就开始对这些知识点进行应用,创建出类和对应的方法。「所有代码都可以关注公众号:bugstack虫洞栈
,回复码下载获取」
二、开发环境
- JDK 1.8.0
- javassist 3.12.1.GA
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<type>jar</type>
</dependency>
三、案例目标
为了练习属性字段和方法的不同的入参、出参,我们使用 javassist
创建如下这样的方法。当然你也可以尝试去扩展其他类型的方法。
public class ApiTest {
private double π = 3.14D;
//S = πr²
public double calculateCircularArea(int r) {
return π * r * r;
}
//S = a + b
public double sumOfTwoNumbers(double a, double b) {
return a + b;
}
}
四、技术实现
GenerateClazzMethod.java & 生成类和方法
/**
* 公众号:bugstack虫洞栈
* 博客栈:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
* 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。如果能为您提供帮助,请给予支持(关注、点赞、分享)!
*/
public class GenerateClazzMethod {
public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.MathUtil");
// 属性字段
CtField ctField = new CtField(CtClass.doubleType, "π", ctClass);
ctField.setModifiers(Modifier.PRIVATE + Modifier.STATIC + Modifier.FINAL);
ctClass.addField(ctField, "3.14");
// 方法:求圆面积
CtMethod calculateCircularArea = new CtMethod(CtClass.doubleType, "calculateCircularArea", new CtClass[]{CtClass.doubleType}, ctClass);
calculateCircularArea.setModifiers(Modifier.PUBLIC);
calculateCircularArea.setBody("{return π * $1 * $1;}");
ctClass.addMethod(calculateCircularArea);
// 方法;两数之和
CtMethod sumOfTwoNumbers = new CtMethod(pool.get(Double.class.getName()), "sumOfTwoNumbers", new CtClass[]{CtClass.doubleType, CtClass.doubleType}, ctClass);
sumOfTwoNumbers.setModifiers(Modifier.PUBLIC);
sumOfTwoNumbers.setBody("{return Double.valueOf($1 + $2);}");
ctClass.addMethod(sumOfTwoNumbers);
// 输出类的内容
ctClass.writeFile();
}
}
这里面有几个核心点,讲解如下;
CtField
,属性字段的创建。这就像我们正常写代码一样,需要设定属性的;名称、类型以及是public
的还是private
的以及static
和final
等。都可以通过Modifier.PRIVATE
+Modifier.STATIC
+Modifier.FINAL
,通过组合来控制。同样这也适用于对方法类型的设置。同时需要在添加属性的地方,设置初始值。- 接下来是我们设置了一个求圆面积的方法,如果说在方法体中需要使用到入参类型。那么需要通过符号 $+数字,来获取入参。这个数字就是当前入参的位置。比如取第一个入参:
$1
,以此类推。 - 之后是我们的多种入参类型,在这开始我们也提到了。如果是基本类型入参都可以使用
CtClass.doubleType
,对象类型入参使用pool.get(类.class.getName)
获取。 - 最终同样我们会把使用字节码编译的 class 输出到工程目录下
ctClass.writeFile()
。 - 在Javassist中并不会给类型做拆箱和装箱操作,需要显式的处理。例如上面案例中,需要将
double
使用Double.valueOf
进行转换。
下面这张基本描述了一个类方法在创建时候不同参数的含义,可以参考。
五、测试结果
1. 反射调用字节码类方法
在测试之前,我们需要写一点反射代码来调用类的方法
// 测试调用
Class clazz = ctClass.toClass();
Object obj = clazz.newInstance();
Method method_calculateCircularArea = clazz.getDeclaredMethod("calculateCircularArea", double.class);
Object obj_01 = method_calculateCircularArea.invoke(obj, 1.23);
System.out.println("圆面积:" + obj_01);
Method method_sumOfTwoNumbers = clazz.getDeclaredMethod("sumOfTwoNumbers", double.class, double.class);
Object obj_02 = method_sumOfTwoNumbers.invoke(obj, 1, 2);
System.out.println("两数和:" + obj_02);
测试结果:
圆面积:4.750506
两数和:3.0
Process finished with exit code 0
2. 查看使用Javassist生成的类
六、总结
- 本篇案例中重点强调了属性字段创建,同时需要给属性字段赋值。
- 在
Javassist
是不会进行类型的自动装箱和拆箱的,需要我们进行手动处理,否则生成类在执行会报类型错误。 - 当需要使用入参的时候,可以使用
$1
来获取。这也是后续做一些监控获取入参的方法。
字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》的更多相关文章
- 字节码编程,Javassist篇三《使用Javassist在运行时重新加载类「替换原方法输出不一样的结果」》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 通过前面两篇 javassist 的基本内容,大体介绍了:类池(ClassPool) ...
- 字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 目录 @ 目录 目录 一.前言 二.开发环境 三.案例目标 四.技术实现 五.测试结果 1. ...
- 字节码编程,Byte-buddy篇一《基于Byte Buddy语法创建的第一个HelloWorld》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 相对于小傅哥之前编写的字节码编程: ASM.Javassist 系列,Byte Bu ...
- 字节码操作JAVAssist
字节码操作Javassist 字节码:字节码是设计被用来将代码高效的传送给多种软件平台.硬件平台,字节码的设计也实现了Java的平台无关性,字节码比机器码更抽象,它通常被认为是包含了一个可执行文件的二 ...
- Java多线程编程——进阶篇二
一.线程的交互 a.线程交互的基础知识 线程交互知识点需要从java.lang.Object的类的三个方法来学习: void notify() 唤醒在此对象监视器上等待的单个 ...
- [19/04/20-星期六] Java的动态性_字节码操作(Javassist类库(jar包),assist:帮助、援助)
一.概念 [基本] /** * */ package cn.sxt.jvm; import javassist.ClassPool; import javassist.CtClass; import ...
- 动态字节码技术Javassist
字节码技术可以动态改变某个类的结构(添加/删除/修改 新的属性/方法) 关于字节码的框架有javassist,asm,bcel等 引入依赖 <dependency> <groupI ...
- JVM Class字节码之三-使用BCEL改变类属性
使用BCEL动态改变Class内容 之前对Class文件中的常量池,Method的字节码指令进行了说明.JVM Class详解之一JVM Class详解之二 Method字节码指令现在我们开始实际动手 ...
- JDK源码学习--String篇(二) 关于String采用final修饰的思考
JDK源码学习String篇中,有一处错误,String类用final[不能被改变的]修饰,而我却写成静态的,感谢CTO-淼淼的指正. 风一样的码农提出的String为何采用final的设计,阅读JD ...
随机推荐
- work of 1/4/2016
part 组员 今日工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 修改UI增强显示鲁棒 6 完成UI页面切换部分 ...
- 重磅!阿里发布《Java开发手册(泰山版)》
最近,阿里的<Java开发手册>又更新了,这个版本历经一年的修炼,取名:<Java开发手册(泰山版)>正式出道. 正所谓无规矩不成方圆,在程序员的世界里,也存在很多规范,阿里出 ...
- Python 代码编辑器怎么选?PyCharm、VS Code、Jupyter Notebook 都各有特色
Python 代码编辑器怎么选?PyCharm.VS Code.Jupyter Notebook 都各有特色,Jupyter 适合做数据分析这些需要可视化的操作,PyCharm 更适合做完整的 Pyt ...
- ASP.NET Core 与 ASPOSE.Words for .NET
Aspose.Total是Aspose公司旗下的最全的一套office文档管理方案,它提供的原生API可以对Word.Excel.PDF.Powerpoint.Outlook.CAD.图片.3D.ZI ...
- java学习(第二篇)语法学习
1.java标识符 类名.变量名以及方法名都被称为标识符. 关于 Java 标识符,有以下几点需要注意: 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($).或者下划线(_)开始 首字符之 ...
- Manjaro Linux 入门使用教程
Manjaro 初体验 Manjaro 是一款基于 Arch LInux 的自由开源发行版,它吸收了 Arch Linux 优秀丰富的软件管理,同时提供了稳定流畅的操作体验.优雅简单是它的追求,稳定实 ...
- python教程(目录)
很早就想出一套python的零基础入门教程,各种原因一直没动手.今天立个flag,2020年一定完成这个目标. 入门篇 完全零基础的小白应该从这里看起. 一.计算机原理 这里不是要让大家去深入的学习计 ...
- (转)对 Linux 专家非常有用的 20 个命令
谢谢你你给了我们在这篇文章前两个部分的喜欢,美言和支持.在第一部分文章中我们讨论了那些都只是切换到 Linux 和linux新手所需的必要知识的用户的命令. 对 Linux 新手非常有用的 20 个命 ...
- js 之 for循环
js之 for循环 普通for 循环 语法 for ([initialization]; [condition]; [final-expression]) statement initializati ...
- jQuery学习(二)
操作DOM对象: 修改文本: jQuery对象的text()和html()方法可以用来获取节点的文本内容和HTML文本.而当你给方法传入参数时,这两个方法可以被用于设置jQuery的文本内容. 还是以 ...