这篇文章主要讲解了“Java字节码编程javassist实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java字节码编程javassist实例分析”吧!Javassist是可以动态编辑Java字节码的类库。它可以在Java程序运行时定义一个新的类,并加载到JVM中;还可以在JVM加载时修改一个类文件。Javassist使用户不必关心字节码相关的规范也是可以编辑类文件的。在Javassist中每个需要编辑的class都对应一个CtCLass实例,CtClass的含义是编译时的类(compile time class),这些类会存储在Class Pool中(Class poll是一个存储CtClass对象的容器)。
CtClass中的CtField和CtMethod分别对应Java中的字段和方法。通过CtClass对象即可对类新增字段和修改方法等操作了。为了减少演示的复杂度,示例以及之后的操作,都在Maven项目下进行,因为我们可以直接引入依赖就可以达到我们导包的目的,很方便,不用再去下载jar包,然后自己手动导入了。1、创建一个maven项目如果你使用的是IDEA,可以像我一样;如果是其他工具,可以自行百度,或者按照自己的经验来创建即可。2、创建一个测试类,代码如下:当运行这个代码的时候,可以看到已经在项目的根目录下创建了一个“com.ssdmbbl.javassist”包,在这个包下创建了“Hello.java”的java文件。
内容如下:回想一下,咱们如果对一个Java正常免费云主机域名操作的话,大概存在哪些操作呢?1、咱们会对一个类添加字段;2、咱们会对一个类添加方法;好像没其他的了吧。其余的就是在方法里写代码了呗。咱们继续套用上面简单示例的代码,在此基础之上进行新增一个方法。新增方法的名字为”hello1″,传递两个参数分别为int和double类型,并且没有返回值。执行后,就可以查看生成的代码了:可以看到,我们并没有指定参数的名字,也会给生成var1、var2依次类推的名字。var1和var2其实class变量表中存放的名字。可以设置的返回值类型:那么执行后的内容就是如下了:代码修改如下:执行效果:你是不是很好奇,set和get方法内部并没有代码,当程序运行的时候,肯定会出错的。
下面就来看一下。我们预想的结果:修改如下:很倒霉,说找不到这个var1这个变量报错的堆栈信息如下:Exception in thread “main” javassist.CannotCompileException: [source error] no such field: var1
at javassist.CtBehavior.setBody(CtBehavior.java:474)
at javassist.CtBehavior.setBody(CtBehavior.java:440)
at com.ssdmbbl.javassist.JavassistTest2.main(JavassistTest2.java:41)
Caused by: compile error: no such field: var1
这个原因我们前面其实提到了,因为在编译的时候,会把变量名抹掉,传递的参数会依次在局部变量表中的顺序。如果传递:那么a,b,c就对应本地变量表中的1,2,3的位置。那么我们获取变量时就不能使用原始的名字了,在Javassist中访问方法中的参数使用的是$1, 2 , 2, 2,…,而不是直接使用原始的名字。我们修改如下:结果成功了:再来一个:修改hello1方法体,使传递的两个参数相加然后赋值给value;执行结果如下:因为我们value是int,$1是int,$2是double,所以做了强制转型处理。测试代码如下:结果如下:三、Javassist中的一些特殊参数示例讲解在官方文档中看到有几个比较特殊的标识符,还有几个比较特殊的标识符需要了解。这个其实咱们已经在上面用到过了,再来细说一下吧。$0代表this,$1, 2 , 2, 2,…,依次对应方法中参数的顺序。
如果有:那么如果想引用a和b和c的话,需要这样:对了还有:静态方法是没有$0的,所以静态方法下$0是不可用的。$args变量表示所有参数的数组,它是一个Object类型的数组(new Object[]{…}),如果参数中有原始类型的参数,会被转换成对应的包装类型。比如原始数据类型为int,则会被转换成java.lang.Integer,然后存储在args中。例如我们测试代码如下:编译后的结果如下:变量 是 所 有 参 数 的 缩 写 , 参 数 用 逗 号 分 割 , 例 如 : m ( 是所有参数的缩写,参数用逗号分割,例如:m( 是所有参数的缩写,参数用逗号分割,例如:m()相当于:m($1,$2,$3,…)。如何使用呢?我们经常做一些代码优化,把较为复杂的方法内部的逻辑,提炼出来,提炼到一个公共的方法里。或者说一个方法调用另一个方法,这两个方法传递的参数是一样的时候就用到了。例如原java:提炼后的:提炼出来的代码,我们也可以在其他地方使用(所谓的公共的代码)。那么我们就造一个这个场景来说明一下用法吧。简单点来说,就是一个方法调用另一个方法,传递全参数时。可以看到我们hello1调用hello2时,需要传递全部参数。此时即可写成$$方法,当然了也可以写成hello2($1,$2)。编译后的结果:$cflow 的全名为:control flow,这是一个只读变量,返回指定方法递归调用的深度。我们以计算n的斐波拉契数列为例,来演示一下如何使用。我们正确的递归算法代码如下:对于上面这段代码,我们可以这样写:编译后的:那么我们只想在递归到前n次的时候打印log,我们该怎么做呢。例如,我们下面写的是”$cflow(f) == 1″时编译后的代码:通过查看源码,发先关键的一个地方是调用了Cflow对象的enter方法:点进enter()的内部发现,调用了get().inc()方法:而inc()方法控制着一个全局变量的增加操作。boolean var6 = false;相当于是一个开关,控制着是否开始和结束。当参数var1
我们可以使用反射来验证一下,测试代码如下:执行的结果:为什么是2次呢?原因上面也说了:if(var1 我执行了,此时的n是:4
我执行了,此时的n是:3
感谢各位的阅读,以上就是“Java字节码编程javassist实例分析”的内容了,经过本文的学习后,相信大家对Java字节码编程javassist实例分析这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是百云主机,小编将为大家推送更多相关知识点的文章,欢迎关注!
小编给大家分享一下bedtools如何批量提取基因组指定位置序列,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!用到软件是bedtools,具体方法如下:其中-fi 指定基因组fast…
免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。