JVM class file & 解析

class file format:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}
package com.caicongyang.study.classloder;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 解析class文件
 * https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7
 *
 * @author caicongyang
 * @version id: ClassAnalyzer, v 0.1 18/1/6 下午4:03 caicongyang1 Exp $$
 */
public class ClassAnalyzer {

    public static final String FILENAME = "/Users/caicongyang1/tmp/Person.class";

    public static final Boolean DEBUG = false;

    /**
     * 字段访问修饰符map
     */
    public static Map<Integer, String> fieldAccessFlagMap = new HashMap();

    /**
     * 方法访问修饰符map
     */
    public static Map<Integer, String> methodAccessFlagsMap = new HashMap();

    /**
     * 类访问修饰符map
     */
    public static Map<Integer, String> accessFlagMap = new HashMap();

    /**
     * 常量map
     */
    public static Map<Integer, Object> constantMap = new HashMap();

    /**
     * 常量key map
     */
    public static Map<Integer, Integer> constantKeyMap = new HashMap();

    @org.testng.annotations.Test
    public void analyze() {

        //初始化各类访问修饰符map
        initAcessFlag();
        initFieldAccessFlag();
        initMethodAccessFlagsMap();

        //开始分析class文件
        DataInputStream input = null;
        try {
            input = new DataInputStream(new BufferedInputStream(new FileInputStream(FILENAME)));
            //解析数据
            analyze(input);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                input.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void analyze(DataInputStream input) throws Exception {
        // 读取幻数
        int magic = u4(input);

        // 读取副、主版本号
        int minor_ver = u2(input);
        int major_ver = u2(input);

        //分析常量池
        analyConstant(input);

        // 读取Class的声明中使用的修饰符掩码并解析
        short access_flags = u2(input);

        //读取类或者接口的全限定名称
        short this_class_index = u2(input);
        short super_class_index = u2(input);
        System.out.println("当前类:"+constantMap.get((int)this_class_index));
        System.out.println("超类:"+constantMap.get((int)super_class_index));
        // read interfaces count:
        short interfaces_count = u2(input);
        System.out.println("接口数:" + interfaces_count);
        // read each interface:
        if (interfaces_count > 0) {
            System.out.println("接口列表:");
            for (int i = 0; i < interfaces_count; i++) {
                short interface_index = u2(input);
            }
        }

        //fields 数量
        Short fieldsCount = u2(input);
        System.out.println("字段数:" + fieldsCount);
        if (fieldsCount > 0) {
            System.out.println("字段列表:");
            for (int i = 0; i < fieldsCount; i++) {
                analyzeField(input, i);
            }
        }

        //method数量
        Short methodsCount = u2(input);
        System.out.println("方法数:" + methodsCount);
        if (methodsCount > 0) {
            System.out.println("方法列表:");
            for (int i = 0; i < methodsCount; i++) {
                analyzeMethod(input, i);
            }
        }

        /**
         * 类属性数量
         */
        Short attributeCount = u2(input);
        if (attributeCount > 0) {

        }



    }

    /**
     * 分析常量
     */
    public void analyConstant(DataInputStream input) throws Exception {
        // 读取常量池表中表项的个数
        short const_pool_count = u2(input);
        // 读取每个常量  The constant_pool table is indexed from 1 to constant_pool_count - 1.
        for (int i = 1; i < const_pool_count; ++i) {
            analyzeEachConstant(input, i); //分析每个常数
        }
        for (Integer key : constantKeyMap.keySet()) {
            constantMap.put(key, constantMap.get(constantKeyMap.get(key)));
        }

        for (Integer key : constantMap.keySet()) {
            Object value = constantMap.get(key);
            if (value instanceof String) {
                String oldValue = (String) value;
                if (oldValue.startsWith("L")) {
                    constantMap.put(key, oldValue.substring(1).replace("/", "."));
                }


            }
        }
    }

    /**
     * 读取常量池
     *
     * cp_info {
     * u1 tag;
     * u1 info[];
     * }
     */
    public void analyzeEachConstant(DataInputStream input, int index) throws IOException {
        byte tag = u1(input); //读取数据类型标签
        switch (tag) {
            case 1: // utf-8
                Short lenth = u2(input); //length
                byte[] buffer = new byte[lenth];
                input.readFully(buffer);
                constantMap.put(index, new String(buffer));
                break;
            case 3: // integer
                Integer intergetVlue = u4(input);
                constantMap.put(index, intergetVlue);
                break;
            case 4: // float
                Integer floatValue = u4(input);
                constantMap.put(index, floatValue);
                break;
            case 5: // long
                Integer high_bytes = u4(input);
                Integer low_bytes = u4(input);
                constantMap.put(index, ((long) high_bytes << 32) + low_bytes);
                break;
            case 6: // double
                Integer DoubleHighBytesValue = u4(input);
                Integer DoubleLowBytesValue = u4(input);
                constantMap.put(index, ((long) DoubleHighBytesValue << 32) + DoubleLowBytesValue);
                break;
            case 7: // class
                Short name_index = u2(input);
                constantKeyMap.put(index, (int) name_index);
                break;
            case 8: // string
                Short string_index = u2(input);
                constantKeyMap.put(index, (int) string_index);
                break;
            case 9: // CONSTANT_Fieldref
                Short class_index = u2(input);
                Short name_and_type_index = u2(input);
                constantKeyMap.put(index, (int) name_and_type_index);
                break;
            case 10: // method reference
                class_index = u2(input);
                name_and_type_index = u2(input);
                constantKeyMap.put(index, (int) name_and_type_index);
                break;
            case 11: // interface method reference
                class_index = u2(input);
                name_and_type_index = u2(input);
                constantKeyMap.put(index, (int) name_and_type_index);
                break;
            case 12: // name and type reference
                name_index = u2(input);
                Short descriptor_index = u2(input);
                constantKeyMap.put(index, (int) name_index);
                break;
            case 15: // CONSTANT_MethodHandle
                byte reference_kind = u1(input);
                Short reference_index = u2(input);
                constantKeyMap.put(index, (int) reference_index);

                break;
            case 16: // CONSTANT_MethodType
                descriptor_index = u2(input);
                constantKeyMap.put(index, (int) descriptor_index);
                break;
            case 18: // CONSTANT_InvokeDynamic
                Short bootstrap_method_attr_index = u2(input);
                name_and_type_index = u2(input);
                constantKeyMap.put(index, (int) name_and_type_index);
                break;
            default:
                throw new RuntimeException("Invalid constant pool flag: " + tag);
        }
    }

    /**
     * 获取属性
     */
    public void analyzeField(DataInputStream input, int index) throws IOException {
        short accessFlag = u2(input);
        String accessFlagValue = fieldAccessFlagMap.get((int) accessFlag);
        Short nameIndex = u2(input); //去读名字在常量池的索引
        Short descriptorIndex = u2(input); //读取描述符在常量池的索引
        Short attributesCount = u2(input);// 读取属性个数
        if (attributesCount > 0) { //读取field attributes 属性
            Short attributeNameIndex = u2(input);
            int attributeLength = u4(input);
            byte[] buffer = new byte[attributeLength];
            input.readFully(buffer);
            System.out.println(new String(buffer));

        }
        System.out.println(accessFlagValue + " 描述:" + constantMap.get((int) descriptorIndex) + " 名字:"
            + constantMap.get((int) nameIndex));

    }

    /**
     * 获取方法
     */
    public void analyzeMethod(DataInputStream input, int index) throws Exception {
        Short accessFlag = u2(input); // accessFlag
        String accessFlagValue = methodAccessFlagsMap.get((int) accessFlag);
        Short nameIndex = u2(input);
        Short descriptorIndex = u2(input);
        Short attributesCount = u2(input);
        if (attributesCount > 0) {
            Short attributeNameIndex = u2(input);
            int attributeLength = u4(input);
            byte[] buffer = new byte[attributeLength];
            input.readFully(buffer);
            // System.out.println(new String(buffer));
        }

        System.out.println(accessFlagValue + " 描述:" + constantMap.get((int) descriptorIndex) + " 名字:"
            + constantMap.get((int) nameIndex));

    }

    /**
     * 初始化所有的字段访问修饰符
     */
    public void initFieldAccessFlag() {
        fieldAccessFlagMap.put(0x0001, "public");
        fieldAccessFlagMap.put(0x0002, "private");
        fieldAccessFlagMap.put(0x0004, "protected");
        fieldAccessFlagMap.put(0x0008, "static");
        fieldAccessFlagMap.put(0x0010, "final");
        fieldAccessFlagMap.put(0x0040, "volatile");
        fieldAccessFlagMap.put(0x0080, "transient");
        fieldAccessFlagMap.put(0x1000, "synthetic");
        fieldAccessFlagMap.put(0x4000, "enum");
    }

    /**
     * 初始化类访问修饰符
     */
    public void initAcessFlag() {

        accessFlagMap.put(0x0001, "public");
        accessFlagMap.put(0x0010, "final");
        accessFlagMap.put(0x0020, "super");
        accessFlagMap.put(0x0200, "interface");
        accessFlagMap.put(0x0400, "abstract");
        accessFlagMap.put(0x1000, "synthetic");
        accessFlagMap.put(0x2000, "annotation");
        accessFlagMap.put(0x4000, "enum");
    }

    /**
     * 初始化method access flag map
     */
    public void initMethodAccessFlagsMap() {
        methodAccessFlagsMap.put(0x0001, "public");
        methodAccessFlagsMap.put(0x0002, "private");
        methodAccessFlagsMap.put(0x0004, "protected");
        methodAccessFlagsMap.put(0x0008, "static");
        methodAccessFlagsMap.put(0x0010, "final");
        methodAccessFlagsMap.put(0x0020, "synchronized");
        methodAccessFlagsMap.put(0x0040, "bridge");
        methodAccessFlagsMap.put(0x0080, "varargs");
        methodAccessFlagsMap.put(0x0100, "native");
        methodAccessFlagsMap.put(0x0400, "abstract");
        methodAccessFlagsMap.put(0x0800, "strict");
        methodAccessFlagsMap.put(0x1000, "synthetic"); //非源码内容,有编译器生成
    }

    /**
     * 读取1个字符
     */
    public static byte u1(DataInputStream input) throws IOException {
        byte value = input.readByte();
        if (DEBUG) {
            System.out.println(value + ":" + Integer.toHexString(value));
        }
        return value;
    }

    /**
     * 读取2个字符
     */
    public static Short u2(DataInputStream input) throws IOException {
        short value = input.readShort();
        if (DEBUG) {
            System.out.println(value + ":" + Integer.toHexString(value));
        }
        return value;
    }

    /**
     * 读取4个字符
     */
    public static int u4(DataInputStream input) throws IOException {
        int value = input.readInt();
        if (DEBUG) {
            System.out.println(value + ":" + Integer.toHexString(value));
        }
        return value;
    }

    /**
     * 读取8个字符
     */
    public static long u8(DataInputStream input) throws IOException {
        long value = input.readLong();
        if (DEBUG) {
            System.out.println(value + ":" + Long.toHexString(value));
        }
        return value;
    }


}
测试结果:
当前类:Person
超类:java/lang/Object
接口数:0
字段数:2
字段列表:
private 描述:java.lang.String; 名字:name
private 描述:java.lang.Integer; 名字:age
方法数:6
方法列表:
public 描述:()V 名字:<init>
public 描述:()Ljava/lang/String; 名字:getName
public 描述:(Ljava/lang/String;)V 名字:setName
public 描述:()Ljava/lang/Integer; 名字:getAge
public 描述:(Ljava/lang/Integer;)V 名字:setAge
public 描述:()V 名字:sayHello




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值