大约5年前,想研究javaassistant,cglib等字节码操作的相关类库,来对class进行增强,当要到要操作字节码的时候,发现无法继续下去了,只能放弃。
学习jvm字码,需要理解class的组成方式,对汇编,操作栈比较了解,无奈,只好重新学习编译原理,汇编等知识,再来看jvm规范,现在理解起来,容易很多了。
编译后被 Java 虚拟机所执行的代码使用了一种平台中立(不依赖于特定硬件及操作系统的)
的二进制格式来表示,并且经常(但并非绝对)以文件的形式存储,因此这种格式被称为 Class
文件格式。Class 文件格式中精确地定义了类与接口的表示形式,包括在平台相关的目标文件格
式中一些细节上的惯例
相关文档
https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-4.html
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]; }
下面,我们开始解析每个字段是如何标识出来的
其中 u4, u2 代表什么意思
u 表示无符号数 后面的数字 表示 占用多少字节
u4 占用4个字节
u2 占用2个字节
minor_version 子版本号 ,2个字节数字
major_version 主版本好 2个字节的数字
相信大部分第一样看到上面的协议时候,能看弄,但是要自己动手解析出每个字段的含义出来,
就无法下手了,
FileInputStream in= new FileInputStream("d:/my.class");
byte[] bytes=new byte[4]; in.read(bytes);
byte[] minorByte=new byte[2]; in.read(minorByte);
byte[] majorVersion=new byte[2]; in.read(majorVersion);
看到上面的解析,是否明白了,其实还是很有规律的,只要你认真看协议文档(要看好多遍才行)
最终解析class 文档就是这样的
ClassFile classFile = new ClassFile(); PcBufferInputStream in = new PcBufferInputStream(new FileInputStream(fileName)); classFile.setMagic(readMagic(in)); classFile.setMinorVersion(readMinorVersion(in)); classFile.setMajorVersion(readMajorVersion(in)); classFile.setConstantPoolCount(readConstantPoolCount(in)); classFile.setCpInfo(readCpInfo(in)); classFile.setAccessFlags(readAccessFlags(in)); classFile.setThisClass(readThisClass(in)); classFile.setSuperClass(readSuperClass(in)); classFile.setInterfacesCount(readInterfacesCount(in)); // u2 interfaces interfaces_count classFile.setInterfaces(readInterfaces(in)); // u2 fields_count classFile.setFieldsCount(readFieldsCount(in)); // field_info fields fields_count classFile.setFields(readFields(in)); // u2 methods_count 1 // method_info methods methods_count classFile.setMethodsCount(readMethodsCount(in)); classFile.setMethods(readMethods(in)); // u2 attribute_count 1 classFile.setAttributeCount(readAttributeCount(in)); // attribute_info attributes attributes_count classFile.setAttributes(readAttributes(in)); classFile.setPcRecord(recordMap); return classFile;
java class 解析源码开源地址
https://gitee.com/venus-suite/java-classViewer
如果喜欢,欢迎stars 哦