美文网首页
Java 动态特性二:字节码操作

Java 动态特性二:字节码操作

作者: 真海ice | 来源:发表于2018-03-02 10:32 被阅读0次

    java本身动态性的两种实现方式:反射字节码操作

    字节码操作:可以实现动态生成一个类(.class文件)和动态的修改类的结构;可以去改变一个类。
    反射:去动态的执行类的内容,不能改变类。一个是改变,一个是执行;多数情况下两者配合使用。

    反射中有Class、 Method、Field、Constructor等类,相似在字节码操作中有CtClass、CtMethod、CtField、CtConstructor等与之相对应。 Ct(Compile time)。

    MakeNewClass:利用动态字节码操作生成一个新的类;
    ChangeClass :去改变一个类的结构
    User: 需要改变的类

    package com.test.byteCode;
    
    import java.io.IOException;
    
    import javassist.CannotCompileException;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtConstructor;
    import javassist.CtField;
    import javassist.CtMethod;
    
    /**
     * java的动态性中对字节码的操作,
     * 利用javasisit生成一个新的.class文件
     * @author zhb
     *
     */
    public class MakeNewClass {
        
        public static void main(String[] args) throws CannotCompileException, IOException {
            
            ClassPool pool = ClassPool.getDefault();
            String className = "com.test.reflect.User";
            // 用类的全路径创建一个类
            CtClass ctClass = pool.makeClass(className);
            
            // 给类创建属性
            CtField ctField = CtField.make("private int id;", ctClass);
            // 给类添加属性
            ctClass.addField(ctField);
            
            // 给类创建构造方法
            // 创建有参的构造方法
            CtConstructor ctConstructor = new CtConstructor(new CtClass[]{CtClass.intType}, ctClass);
            ctConstructor.setBody("this.id = id;");
            // 给类添加构造方法
            ctClass.addConstructor(ctConstructor);
                
            // 给类创建方法
            CtMethod ctMethod1 = CtMethod.make("private void setId(String id){this.id = id;}", ctClass);
            CtMethod ctMethod2 = CtMethod.make("private String getId(){return id;}", ctClass);
            CtMethod ctMethod3 = CtMethod.make("public void sayHello(){System.out.println(\"你好\");}", ctClass);
            // 给类添加方法
            ctClass.addMethod(ctMethod1);
            ctClass.addMethod(ctMethod2);
            ctClass.addMethod(ctMethod3);
            
            // 生成class文件,到D盘Myclass的文件夹下
            ctClass.writeFile("E:/Myclass");
            System.out.println("class文件创建成功");
        }
    
    }
    
    package com.test.byteCode;
    
    import java.lang.reflect.Method;
    
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    
    /**
     * 更改User的class文件的内容
     * @author zhb
     *
     */
    public class ChangeClass {
        
        /**
         * 用字节码动态添加一个方法,并且执行这个方法
         * @throws Exception
         */
        public static void test1() throws Exception{
    
            ClassPool classPool = ClassPool.getDefault();
            String path = "com.test.reflect.User";
            CtClass ctClass = classPool.get(path);
            
            // 给类添加一个新方法
            CtMethod ctMethod = CtMethod.make("public int add(int a, int b){return a+b;}", ctClass);
            ctClass.addMethod(ctMethod);
            
            // 通过反射执行刚刚加入的add方法
            // ctClass转成反射类
            Class clazz = ctClass.toClass();
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("add", int.class, int.class);
            // 执行刚刚加入的add方法
            Object result = method.invoke(obj, 8, 4);
            ctClass.defrost();
            System.out.println(result);
        }
        
        /**
         * 用字节码动态添加动态给一个方法的前面或者后面添加方法,并且执行这个方法
         * @throws Exception
         */
        public static void test2() throws Exception{
            
            ClassPool classPool = ClassPool.getDefault();
            String path = "com.test.reflect.User";
            CtClass ctClass = classPool.get(path);
            // 修改方法,在某个方法的前面或者后面加入新的方法;像spring AOP
            // 获取原有的方法,hello
            CtMethod ctMethod = ctClass.getDeclaredMethod("hello", new CtClass[]{classPool.get("java.lang.String")});
            ctMethod.insertBefore("System.out.println(\"方法之前执行\");");
            ctMethod.insertAfter("System.out.println(\"方法之后执行\");");
                    
            Class clazz = ctClass.toClass();
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("hello", String.class);
            method.invoke(obj,"张三");
        }   
    
        public static void main(String[] args) throws Exception {
            test1();
    //      test2();
        }
            
    }
    
    package com.test.reflect;
    
    public class User {
        
        private int id;
        private String name;
        
        // 无参的构造方法,容易被忘记
        public User(){      
        }
        
        //有参的构造方法
        public User(int id, String name){
            this.id = id;
            this.name = name;
        }
        
        // 类中一个普通的方法
        public String hello(String name){
            System.out.println("hello:"+ name);
            return "方法调用成功";
        }
        
        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;
        }
        
    }
    

    相关文章

      网友评论

          本文标题:Java 动态特性二:字节码操作

          本文链接:https://www.haomeiwen.com/subject/evwoxftx.html