[19/04/20-星期六] Java的动态性_字节码操作(Javassist类库(jar包),assist:帮助、援助)
一、概念
【基本】
/**
*
*/
package cn.sxt.jvm; import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod; public class Test_0420_Javassist {
public static void main(String[] args) throws Exception {
ClassPool pool =ClassPool.getDefault();//获得一个类池
CtClass cc=pool.makeClass("cn.sxt.jvm.Test_0420_Emp2");//cc代表要要创建的一个类 ct:compile time(编译和运行) //创建属性 注意""里边的;和{ }问题,跟在编译器里边写代码是一样的
CtField field=CtField.make("private int empNo;", cc);//直接在这个类中书写另一个类的源码
CtField field2=CtField.make("private String empName;", cc);
cc.addField(field);
cc.addField(field2); //创建方法
CtMethod method=CtMethod.make("public int getEmpNo(){return empNo;}", cc);
CtMethod method2=CtMethod.make("public void setEmpNo(int empNo){this.empNo=empNo;}", cc);
cc.addMethod(method);
cc.addMethod(method2); //添加构造器
CtConstructor constructor=new CtConstructor(new CtClass[] {CtClass.intType,
pool.get("java.lang.String")}, cc);//有参数构造器 constructor.setBody("{this.empNo=empNo;this.empName=empName;}");
cc.addConstructor(constructor); cc.writeFile("F:/MyEclipse/WorkSpace");//把写好的类写出到文件,写出去的是.class文件,不认识!若要认识它需要反编译工具XJad
System.out.println("生成类成功!"); }
}
【示例】
/***
* 一个示例
*/
package cn.sxt.jvm; public class Test_0420_Emp {
private int id;
private String name; public void print(int a) {
System.out.println("输出:"+a); } public Test_0420_Emp() { } public Test_0420_Emp(int id, String name) {
super();
this.id = id;
this.name = name;
} public int getId() {
return id;
} public void setId(int id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} }
package cn.sxt.jvm; public @interface Test_0420_Annotation {
String name();
int year(); }
【API】
/***
* 测试API
*/
package cn.sxt.jvm; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays; import javax.security.sasl.AuthorizeCallback; import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod; public class Test_0420_Javassist2 {
public static void test01() throws Exception{
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp");//获得一个已经存在的类去操作,不要带"package"," "中不要有空格 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());//获得接口 }
public static void test02() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); //CtMethod method=CtMethod.make("public int add(int a,int b){return a+b;}", cc);
CtMethod method=new CtMethod(CtClass.intType, "add",new CtClass[]{CtClass.intType,CtClass.intType}
,cc);//4个参数含义:返回值类型,方法名字,传入参数类型,类的对象cc. new CtClass[]代表数组,固定套路
method.setModifiers(Modifier.PUBLIC); //设置方法的修饰,公开or私有 Modifiers:修饰符
method.setBody("{System.out.println(\" 求和结果为:\"); return $1+$2;}");//设置方法的结构体。 这3行与上边的一行效果一样
cc.addMethod(method);//$1和$2代表2个形参,是占位符 $0代表this关键字 //通过反射调用新建的方法
Class clz=cc.toClass();
Object obj=clz.newInstance();//通过调用Test_0420_Emp的无参构造器去创建新的Test_0420_Emp对象
Method m=clz.getDeclaredMethod("add",int.class,int.class);
Object result=m.invoke(obj, 200,300);
System.out.println(result);
}
//修改已有的方法信息
public static void test03() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); CtMethod method=cc.getDeclaredMethod("print",new CtClass[]{CtClass.intType});
method.insertAt(11," System.out.println(\"开始\"); "); //在第11行前加代码,第11行代码是:System.out.println("输出:"+a);
method.insertBefore("System.out.println(\"输入:\"+$1);");//修改方法,把" "中的代码加到整个方法体的前边(包括新插入的第11行代码),$1形参占位符
method.insertAfter("System.out.println(\"结束!\");");//修改方法,方法体后边加代码 //通过反射调用新建的方法
Class clz=cc.toClass();
Object obj=clz.newInstance();//通过调用Test_0420_Emp的无参构造器去创建新的Test_0420_Emp对象
Method m=clz.getDeclaredMethod("print",int.class);
m.invoke(obj, 200);
} //修改已有的属性
public static void test04() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp");
//CtField field=CtField.make("private int age=18;", cc); 新建属性方式之一
CtField field=new CtField(CtClass.intType, "age",cc);//方式之二
field.setModifiers(Modifier.PRIVATE);
//cc.addField(field,"18");//默认值18
cc.addField(field); //cc.getDeclaredField("id");//获取相应属性 cc.addMethod(CtNewMethod.getter("getAge", field));//也可以通过这种方式增加属性的get,set方法
cc.addMethod(CtNewMethod.setter("setAge", field)); } //构造器,也可以在构造器前后加代码
public static void test05() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp"); CtConstructor[] cs=cc.getConstructors();//得到所有的构造器
for (CtConstructor tempConstructor : cs) {
System.out.println(tempConstructor.getLongName()); }
}
//读取注解
public static void test06() throws Exception {
ClassPool pool=ClassPool.getDefault();
CtClass cc=pool.get("cn.sxt.jvm.Test_0420_Emp");
Object[] all=cc.getAnnotations();
Test_0420_Annotation a=(Test_0420_Annotation)all[0];//0 表示就一个注解,编译器可以找到
String name=a.name();//读取注解
int year=a.year();
System.out.println(name+"->"+year); } public static void main(String[] args) throws Exception {
//test01();
//test02();
//test03();
test06(); } }
[19/04/20-星期六] Java的动态性_字节码操作(Javassist类库(jar包),assist:帮助、援助)的更多相关文章
- Java zxing生成二维码所需的jar包
免费的,不需要积分. 共有2个jar包, 链接: https://pan.baidu.com/s/1QJcEkRQOp1NdrNAgGC6LvQ 密码: 4524
- [19/04/17-星期三] Java的动态性_反射(Reflection)机制
一.前言 动态语言:程序运行时,可以改变程序结构或变量类型.典型的代表:Python,ruby,JavaScript 如JavaScript代码: function test(){ var s=&qu ...
- [19/04/18-星期四] Java的动态性_动态编译(DynamicCompiler,Dynamic:动态的,Compiler:编译程序)
一.概念 应用场景:如在线评测系统,客户端编写代码,上传到服务器端编译运行:服务器动态加载某些类文件进行编译 /*** * */ package cn.sxt.jvm; import java.io. ...
- Java动态性 字节码操作
Java动态性的两种常见方式:-字节码操作 - 反射;字节码操作比反射开销小,性能高,JAVAasist性能高于反射,低于ASM 运行时操作字节码可是实现 : 动态生成新的类:动态的改变某个类的结构 ...
- 深入理解java:1.2. 字节码执行引擎
执行引擎是Java虚拟机的核心组成部分之一. 首先,想想C++和Java在编译和运行时到底有啥不一样? 下图左边,C++发布的就是机器指令, 而下图右边Java发布的是字节码,字节码在运行时通过JVM ...
- 尚学堂 216 java中的字节码操作
所谓的字节码操作就是操作我们已经加载的字节码 接下来我们重点来讲解javaassist类库 使用需要下载jar包,把jar包添加到对应的工程之后 package com.bjsxt.test; pub ...
- [19/04/19-星期五] Java的动态性_脚本(Script,脚本)引擎执行JavaScript代码
一.概念 Java脚本引擎是jdk 6.0之后的新功能. 使得Java应用程序可以通过一套固定的接口与各种脚本引擎交互,从而达到在Java平台上调用各种脚本语言的目的. Java脚本API是连接Jav ...
- java中i=i++字节码分析
原文出处: Ticmy 1 2 int i = 0; i = i++; 结果还是0为什么? 程序的执行顺序是这样的:因为++在后面,所以先使用i,"使用"的含义就是i++这个表达式 ...
- Java方法调用的字节码指令学习
Java1.8环境下,我们在编写程序时会进行各种方法调用,虚拟机在执行这些调用的时候会用到不同的字节码指令,共有如下五种: invokespecial:调用私有实例方法: invokestatic:调 ...
随机推荐
- Java学习--java中的集合框架、Collection接口、list接口
与数组相比:1.数组的长度固定,而集合的长度可变2.数组只能通过下表访问元素,类型固定,而有的集合可以通过任意类型查找所映射的具体对象 java集合框架:collection(list序列,queue ...
- 高并发系列之——缓存中间件Redis
1 概念和使用场景 下载路径 2 基本存储类型 String List Set SortedSet Hash 3 事务 单线程执行,即只能保证一个client发起的事务中的命令可以连续的执行,而中间不 ...
- java中程序上线报错: tomcat中java.lang.OutOfMemoryError: PermGen space
在程序测试没问题之后,上线试运行,在运行的过程中某个功能一点击就报如下错,然后重启服务器就好了,一会又是如此,解决方法如下(亲测) PermGen space的全称是Permanent Generat ...
- poj 1088(DP+递归)
这题状态方程很容易得到:DP[i][j] = max(DP[i-1][j],DP[i+1][j],DP[i][j-1],DP[i][j+1]) + 1 难点在于边界条件和剪枝,因为这方程的条件是点在m ...
- webpack打包踩坑之TypeError: Cannot read property 'bindings' of null
file loader介绍:https://www.webpackjs.com/loaders/file-loader/ babel loader介绍:https://webpack.js.org/l ...
- Asp.Net实现在线网站安装(上)
在很多年前,笔者在使用z-blog搭建个人部落格的时候,最大的感受就是z-blog在线安装功能! 因为在那个时候,以几K每秒的速度上传一个几M或者十几M的压缩包到虚拟主机上,是一个很痛苦的事情.特别是 ...
- Mac里用终端ssh远程连接Centos服务器
在mac终端下输入 ssh -l root *.*.*.* 就可以远程连接Centos服务器了,端口没变还是:22 如果改变端口用下面方法输入: ssh -p 448(你改变的端口) -l root( ...
- Jquery插件 “IT小鲜肉 Tree”,猛烈完善中
今天又给Jquery插件“IT小鲜肉 Tree”添加了自定义图标.自定义标签显示功能:目前“IT小鲜肉 Tree”已经具备有checkbox.drag and drop 等基本功能. 废话不说,直接上 ...
- html5 区块与内联div 与span html块级元素
HTML <div> 和 <span> HTML 列表 HTML 类 可以通过 <div> 和 <span> 将 HTML 元素组合起来. HTML 块 ...
- seacms 6.45 命令执行漏洞分析
前言 这是一个比较老的漏洞了,不过漏洞原理还是挺有意思的. 正文 漏洞位于 search.php 文件中. 首先包含了 common.php, 这个文件里面做了一些初始化工作,其中最重要的是对提交参数 ...