字节码操作

字节码操作在现今各大流行框架中都有应用,了解和学会字节码操作对深入了解框架的原理有很大的帮助

Java动态性实现的两种方式

  1. 字节码操作
  2. 反射

字节码操作要比反射占用的系统资源开销要小,执行效率也要高得多,但也并不是说他们谁好谁坏,在实际开发中,他们各有各的好坏。但不管怎么样,他们操作的都是JVM即虚拟机编译好的class文件。

字节码操作可以实现的功能

  1. 动态生成一个新的类
  2. 动态改变类的结构(添加、删除、修改新的属性)

在Java中我们常借助一些字节码操作类库来帮助我们进行字节码操作

常见的类库有:
BCEL、ASM、CGLIB(Code generation Library)、Javassist

BCEL和ASM的执行效率最高,因为他们都是基于底层的命令来实现的,但是学习难度较大需要对JVM底层的命令较为熟悉
CGLIB是基于ASM的框架
Javassist和CGLIB差不多,但是由于Javassist可以基于源码来操作字节码,也就是不需要懂太多的JVM的底层的命令也能实现Java的字节码操作,所以基于它的易用性,现在大多数的框架都有在使用它,所以我们一下的代码测试也决定使用Javassist

代码实例测试-生成一个新的类

1)首先需要导入Javassist的jar,或者添加Javassist的Maven依赖这里不再进行展示
2)通过程序我们可以很直观且非常易懂的就能学会Java字节码操作,相关具体介绍请看代码中的相关注释

package com.maple.byteCodeOperation;


import java.io.IOException;

import org.junit.Test;

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

/**
 * Java动态性编程之字节码操作 使用工具Javassist
 * 
 * @author MapleSky
 *
 */
public class TestJavassist {

    @Test
    public void test() throws CannotCompileException, IOException, NotFoundException {
        //获取类池
        ClassPool pool = ClassPool.getDefault();
        //创建一个UserClass对象
        CtClass cc = pool.makeClass("com.maple.byteCodeOperation.User");

        //创建属性
        CtField f1 = CtField.make("private int id;", cc);
        CtField f2 = CtField.make("private String name;", cc);
        cc.addField(f1);
        cc.addField(f2);
        //创建方法
        CtMethod m1 = CtMethod.make("public void test(){}", cc);
        cc.addMethod(m1);
        //创建构造器
        CtConstructor constructor = new CtConstructor(new CtClass[] {CtClass.intType,pool.get("java.lang.String")}, cc);
        cc.addConstructor(constructor);
        cc.writeFile("e:/User.java");
        System.out.println("生成类成功");
    }

}

反编译字节码文件

3)查看结果,成功运行以上代码之后你会发现在你设定的文件目录中会出现一个User.class文件,但是当你双击打开查看时,你会发现里面是一堆乱码,原因就在于这是一个class字节码文件,里面的东西只有计算机能够看懂,所以我们要向查看需要借助字节码反编译工具,在这里我给大家推荐一款,目的不再软件本身,在于程序本身,所以大家不必过多在意,http://jd.benow.ca/

java 字节码 执行 java操作字节码_jvm

通过反射调用class文件

之前我们学了反射,那么在这里既然我们已经生成了一个class文件,那么他就可以用反射来进行先关的读取和操作,由于过程较为简单,这里不再实践,只需要普通的反射调用即可