java class 文件格式解析
前言
大约5年前,想研究javaassistant,cglib等字节码操作的相关类库,来对class进行增强,当要到要操作字节码的时候,发现无法继续下去了,只能放弃。
学习jvm字码,需要理解class的组成方式,对汇编,操作栈比较了解,无奈,只好重新学习编译原理,汇编等知识,再来看jvm规范,现在理解起来,容易很多了。
Class文件规范
编译后被 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个字节
- magic 占用4个字节,(ca fe ba be )

minor_version 子版本号 ,2个字节数字

major_version 主版本好 2个字节的数字

- constant_pool_count 常量池数目 2个字节的数字

- constant_pool[constant_pool_count-1] 常量池数组

- access_flags 访问标识 2个字节数字
- this_class class名称的索引,
- super_class 超类的名称索引
- interfaces_count 接口的数目
- interfaces[interfaces_count] 接口的数组
- fields_count 字段数目
- fields[fields_count] 字段的数组
- methods_count 方法的数目
- methods[methods_count] 方法的数组
- attributes_count 属性的数目
- attributes[attributes_count] 属性的数组
如何自己动手解一个class文件
相信大部分第一样看到上面的协议时候,能看弄,但是要自己动手解析出每个字段的含义出来,
就无法下手了,
- 读取class文件
FileInputStream in= new FileInputStream("d:/my.class");
- 读取 magic ,(magic u4 占用4个字节)
byte[] bytes=new byte[4];
in.read(bytes);
- 读取 minor_version u2 占用2个字节
byte[] minorByte=new byte[2];
in.read(minorByte);
- 读取 major_version u2 占用2个字节
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 哦
java class 文件格式解析的更多相关文章
- (4) 深入理解Java Class文件格式(三)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21557357 首先, 让我们回顾一下关于class文件格式的之前两篇博客的主要内容. 在 ...
- Java 面试知识点解析(三)——JVM篇
前言: 在遨游了一番 Java Web 的世界之后,发现了自己的一些缺失,所以就着一篇深度好文:知名互联网公司校招 Java 开发岗面试知识点解析 ,来好好的对 Java 知识点进行复习和学习一番,大 ...
- (10) 深入了解Java Class文件格式(九)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22432599 经过前八篇关于class文件的博客, 关于class文件格式的内容也基本上讲 ...
- (9) 深入了解Java Class文件格式(八)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22205831 在本专栏的第一篇文章 深入理解Java虚拟机到底是什么 中, 我们主要讲解了 ...
- (8) 深入理解Java Class文件格式(七)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22091529 本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍. 本 ...
- (7) 深入了解Java Class文件格式(六)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21888943 经过前几篇文章, 终于将常量池介绍完了, 之所以花这么大的功夫介绍常量池, ...
- (6) 深入理解Java Class文件格式(五)
前情回顾 本专栏的前几篇博文, 对class文件中的常量池进行了详细的解释. 前文讲解了常量池中的7种数据项, 它们分别是: CONSTANT_Utf8_info CONSTANT_NameAndTy ...
- (5) 深入理解Java Class文件格式(四)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21658415 前情回顾 在上一篇博客深入理解Java Class文件格式(三) 中, ...
- (3) 深入理解Java Class文件格式(二)
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/21487287 在上一篇文章 深入理解Java Class文件格式(一) 中, 介绍了c ...
随机推荐
- [SPDK/NVMe存储技术分析]006 - 内存屏障(MB)
在多核(SMP)多线程的情况下,如果不知道CPU乱序执行的话,将会是一场噩梦,因为无论怎么进行代码Review也不可能发现跟内存屏障(MB)相关的Bug.内存屏障分为两类: 跟编译有关的内存屏障: 告 ...
- 面试官:说一下Synchronized底层实现,锁升级的具体过程?
面试官:说一下Synchronized底层实现,锁升级的具体过程? 这是我去年7,8月份面试的时候被问的一个面试题,说实话被问到这个问题还是很意外的,感觉这个东西没啥用啊,直到后面被问了一波new O ...
- sleep 和 wait 的区别?
Sleep是休眠线程,wait是等待,sleep是thread的静态方法,wait则是object的方法. Sleep依旧持有锁,并在指定时间自动唤醒.wait则释放锁.
- XML的解析方式有哪几种?有什么区别?
有DOM.SAX等. DOM:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种标准方式. DOM中的核心概念就是节点.DOM在分析XML文档 ...
- SpringBoot starter 作用在什么地方?
依赖管理是所有项目中至关重要的一部分.当一个项目变得相当复杂,管理依赖会成为一个噩梦,因为当中涉及太多 artifacts 了. 这时候 SpringBoot starter 就派上用处了.每一个 s ...
- Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法 ?
面试官:想了解对 ES 集群的运维能力. 解答: 1.关闭缓存 swap; 2.堆内存设置为:Min(节点内存/2, 32GB); 3.设置最大文件句柄数: 4.线程池+队列大小根据业务需要做调整: ...
- maven-something
<!--dependencyManagement提供一种管理依赖版本好的方式--> <!-- 通常出现在项目的最顶层父POM,--> <!-- 可以让所有在子项目中引用的 ...
- 手撕代码之线程:thread类简单使用
转载于:https://blog.csdn.net/qq_22494029/article/details/79273127 简单多线程例子: detch()启动线程: 1 #include < ...
- C++各种输入
https://blog.csdn.net/qq_29735775/article/details/81165882 1.cin 2.cin.get() 3.cin.getline() 4.getli ...
- 线程池提交任务的两种方式:execute与submit的区别
Java中的线程池在进行任务提交时,有两种方式:execute和submit方法. 一.execute和submit的区别 execute只能提交Runnable类型的任务,无返回值.submit既可 ...