天天看點

Java 位元組碼操控架構ASM(一):建立class檔案

1、什麼是 ASM ?

ASM 是一個 Java 位元組碼操控架構。它能被用來動态生成類或者增強既有類的功能。ASM 可以直接産生二進制 class 檔案,也可以在類被加載入 Java 虛拟機之前動态改變類行為。ASM 從類檔案中讀入資訊後,能夠改變類行為,分析類資訊,甚至能夠根據使用者要求生成新類。

2、Java 位元組碼小知識

a、類型描述符

Java 位元組碼操控架構ASM(一):建立class檔案

b、方法描述符

Java 位元組碼操控架構ASM(一):建立class檔案

3、建立class檔案

首先去官網下載下傳一下jar包:http://forge.ow2.org/project/download.php?group_id=23&file_id=21558

接下來看代碼:

package com.asm.createclass;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by ouer1994 on 2017/2/18.
 */

/*
     package pkg;
     public interface Comparable extends Mesurable {
        int LESS = -1;
        int EQUAL = 0;
        int GREATER = 1;
        int compareTo(Object o);
     }
 */
public class GenerateClass {
    public static void main(String args[]) {
        ClassWriter classWriter = new ClassWriter(0);
        // 建立類的頭 public interface Comparable extends Mesurable
        // param 1: Java 版本
        // param 2: public abstract interface
        // param 3: 全路徑類名
        // param 4: 泛型
        // param 5: 父類,接口隐式繼承自Object
        // param 6: 接口數組
        classWriter.visit(Opcodes.V1_8,
                Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT + Opcodes.ACC_INTERFACE,
                "com/asm/createclass/Comparable", null, "java/lang/Object", new String[]{"com/asm/createclass/Mesurable"});
        // 建立 int LESS = -1;
        // param 1: public static final
        // param 2: 字段名稱
        // param 3: 字段類型
        // param 4: 泛型
        // param 5: 字段的值
        // 由于這裡沒有注釋,我們立即調用傳回FieldVisitor的visitEnd方法,沒有調用visitAnnotation或visitAttribute方法。
        classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "LESS", "I", null, new Integer(-1)).visitEnd();
        classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "EQUAL", "I", null, new Integer(0)).visitEnd();
        classWriter.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC + Opcodes.ACC_FINAL, "GREATER", "I", null, new Integer(1)).visitEnd();
        classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT, "compareTo", "(Ljava/lang/Onbject;)I", null, null).visitEnd();
        classWriter.visitEnd();
        byte[] data = classWriter.toByteArray();
        try {
            FileOutputStream fos = new FileOutputStream(new File("Comparable.class"));
            fos.write(data);
            fos.flush();
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 使用建立好的class檔案
        Class clazz = new MyClassLoader().defineClass("com.asm.createclass.Comparable", data);
        try {
            Field field = clazz.getField("LESS");
            Integer o = (Integer) field.get(null);
            System.out.println(o.intValue()); // 輸出-1

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
       }
    }

    static class MyClassLoader extends ClassLoader {
    public Class defineClass(String name, byte[] bytes) {
        return defineClass(name, bytes, 0, bytes.length);
    }
}
}
           

運作代碼之後會建立一個 【Comparable.class】 檔案。你可以使用IntellJ來檢視,發現和我們預期的效果一緻。