前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Java 字节码操作示例

Java 字节码操作示例

作者头像
bboy枫亭
发布2021-12-07 15:23:22
发布2021-12-07 15:23:22
95900
代码可运行
举报
文章被收录于专栏:csdn_blogcsdn_blog
运行总次数:0
代码可运行
  • Java 动态性的两种常见实现方式 (1)字节码操作 (2)反射 运行时操作字节码可以让我们实现如下功能: (1)动态生成新的类 (2)动态改变某个类的结构(添加/删除/修改 新的属性/方法)
  • 优势 (1)比反射开销小,性能高 (2)Javassist 性能高于反射,低于ASM

常见的字节码操作类库

  • BCEL
    • Byte Code Engineering Library(BCEL),这是 Apache Software Foundation 的 Jakarta 项目的一部分。BECL 是 Java classworking 广泛使用的一种框架,他可以让您深入 JVM 汇编语言进行类操作的细节。BCEL 与Javassist 有不同的处理字节码的方法,BCEL 在实际的 JVM 指令层次上进行操作 ( BCEL 拥有丰富的 JVM指令级支持 ),而 Javaassist 所强调的是源代码级别的工作。
  • ASM
    • 是一个轻量级 Java 字节码操作框架,直接涉及到 JVM 底层的操作和指令

前两个效率最高,学起来也较难

  • CGLIB(Code Generation Library)
    • 是一个强大的,高性能,高质量的 Code 生成类库,基于 ASM 实现。
  • Javassist
    • 是一个开源的分析、编辑和创建 Java 字节码的类库。性能较 ASM 差,跟 cglib 差不多,但是使用简单。很多开源框架都在使用它。

http://www.javassist.org/

Javassist (Java Programming Assistant) makes Java bytecode manipulation simple. It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it. Unlike other similar bytecode editors, Javassist provides two levels of API: source level and bytecode level. If the users use the source-level API, they can edit a class file without knowledge of the specifications of the Java bytecode. The whole API is designed with only the vocabulary of the Java language. You can even specify inserted bytecode in the form of source text; Javassist compiles it on the fly. On the other hand, the bytecode-level API allows the users to directly edit a class file as other editors.

javassist 使用实例

代码语言:javascript
代码运行次数:0
运行
复制
package com.bigdataBC.demo;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;

/**
 * 测试使用 javassist 生成一个新的类
 * @author bboy枫亭
 * 2020年9月27日上午9:52:43
 */
public class demo01 {
	public static void main(String[] args) throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.makeClass("com.bigdataBC.bean.Emp");
		
		// 创建属性	(源码级操作)
		CtField f1 = CtField.make("private int empno;", cc);
		CtField f2 = CtField.make("private String ename;", cc);
		cc.addField(f2);
		cc.addField(f1);
		
		CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc);
		CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno=empno;}", cc);
		cc.addMethod(m1);
		cc.addMethod(m2);
		
		// 添加构造器
		CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")}, cc);
		constructor.setBody("{this.empno=empno;this.ename=ename;}");
		cc.addConstructor(constructor);
		
		cc.writeFile("d:/myjava");	// 将上面构造好的类写入到d:/myjava中
		System.out.println("生成类成功");
		
	}
}

运行结果:

然后可以使用反编译工具查看,我这里用idea就可以看个差不多。

这就是我们生成的字节码文件内容。

测试 javassist 的 API

代码语言:javascript
代码运行次数:0
运行
复制
package com.bigdataBC.demo;

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 bboy枫亭
 * 2020年9月27日上午11:13:20
 */
public class demo02 {
	// 处理类的基本用法
	public static void test01() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.bigdataBC.demo.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()); // 获得接口
	}
	// 测试产生新的方法
	public static void test02() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.bigdataBC.demo.Emp");
		
//		CtMethod m = CtNewMethod.make("public int add(int a,int b){return a+b;}", cc);
		
		CtMethod m = new CtMethod(CtClass.intType,"add",
				new CtClass[]{CtClass.intType,CtClass.intType},cc);
		m.setModifiers(Modifier.PUBLIC);
		m.setBody("{System.out.println(\"www.sxt.cn\");return $1+$2;}"); //占位符$
		
		cc.addMethod(m);
		
		//通过反射调用新生成的方法
		Class clazz = cc.toClass();
		Object obj = clazz.newInstance();	//通过调用Emp无参构造器,创建新的Emp对象
		Method method = clazz.getDeclaredMethod("add", int.class,int.class);
		Object result = method.invoke(obj, 200,300);
		System.out.println(result);
		
	}
	
	/**
	 * 修改已有的方法的信息,修改方法体的内容
	 * @throws Exception
	 */
	public static void test03() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.bjsxt.test.Emp");
		
		CtMethod cm = cc.getDeclaredMethod("sayHello",new CtClass[]{CtClass.intType});
		cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");");
		cm.insertAt(9, "int b=3;System.out.println(\"b=\"+b);");
		cm.insertAfter("System.out.println(\"end!!!\");");
		
		//通过反射调用新生成的方法
		Class clazz = cc.toClass();
		Object obj = clazz.newInstance();  //通过调用Emp无参构造器,创建新的Emp对象
		Method method = clazz.getDeclaredMethod("sayHello", int.class);
		method.invoke(obj, 300);
	}

	/**
	 * 属性的操作
	 * @throws Exception
	 */
	public static void test04() throws Exception{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.bjsxt.test.Emp");
		
//		CtField f1 = CtField.make("private int empno;", cc);
		CtField f1 = new CtField(CtClass.intType,"salary",cc);
		f1.setModifiers(Modifier.PRIVATE);
		cc.addField(f1);
		
//		cc.getDeclaredField("ename");   //获取指定的属性
		
		//增加相应的set和get方法
		cc.addMethod(CtNewMethod.getter("getSalary", f1));;
		cc.addMethod(CtNewMethod.getter("setSalary", f1));;
		
	}
	
	/**
	 * 构造方法的操作
	 * @throws Exception
	 */
	public static void test05() throws Exception {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("com.bjsxt.test.Emp");
		
		CtConstructor[] cs = cc.getConstructors();
		for (CtConstructor c : cs) {
			System.out.println(c.getLongName());
		}
	}
	
	
	public static void test06() throws Exception{
		 CtClass cc = ClassPool.getDefault().get("com.bjsxt.test.Emp"); 
		 Object[] all = cc.getAnnotations();
		 Author a = (Author)all[0]; 
		 String name = a.name();
		 int year = a.year();
		 System.out.println("name: " + name + ", year: " + year);

	}
	
	public static void main(String[] args) throws Exception {
		test02();
	}
}
代码语言:javascript
代码运行次数:0
运行
复制
package com.bigdataBC.demo;
public @interface Author { 
          String name(); 
           int year();
 }
代码语言:javascript
代码运行次数:0
运行
复制
package com.bigdataBC.demo;

public class Emp {
	private int empno;
	private String ename;
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public Emp() {
	}
	public Emp(int empno, String ename) {
		super();
		this.empno = empno;
		this.ename = ename;
	}
	
	
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/09/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常见的字节码操作类库
  • javassist 使用实例
  • 测试 javassist 的 API
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档