发表文章之后,发现很多图片显示不了,请阅读我的公众号文章,以获得本文最佳体验:
本文假定读者对Java Class文件格式有一些基本的了解,建议结合相关书籍进行对照阅读。
Class文件格式信息
实例代码
package chapter6;
public class TestClass {
private int m;
public int inc() {
return m + 1;
}
}
使用JDK1.8编译成class文件,然后通过WinHex打开
魔数(magic)
类型:u4
字节地址:00000000~00000003
值:0xCAFEBABE
Class文件版本
次版本号(minor_version)
类型:u2
字节地址:00000004~00000005
值:0x0000
主版本号(major_version)
类型:u2
字节地址:00000006~00000007
值:0x0034
将0x0034转换为十进制,计算得到52,对应版本号为JDK 1.8。
常量池
常量池容量计数值(constant_pool_count)
类型:u2
字节地址:00000008~00000009
值:0x0016
将0x0016转换为十进制,计算得到22。由于容量计数是从1开始(如果没有特殊情况,通常都是从0开始),因此常量池中有21项常量,索引值范围为1~21。
常量池中每一项常量都是一个表,表开始的第一位是一个u1类型的标志位(tag)。
第1项常量
tag类型:u1
tag字节地址:0000000A
tag值:0x07
查表可知这个常量属于CONSTANT_Class_info结构,代表一个类或者接口的符号引用。
name_index类型:u2
name_index字节地址:0000000B~0000000C
name_index值:0x0002
0x0002指向了常量池中的第2项常量。
第2项常量
tag类型:u1
tag字节地址:0000000D
tag值:0x01
查表可知这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。
length类型:u2
length字节地址:0000000E~0000000F
length值:0x0012
将0x0012转换为十进制,计算得到18。
bytes类型:u1
bytes字节地址:00000010~00000021(length表明地址范围为18个字节)
bytes值:下方图片浅蓝底对应的所有字节内容
通过WinHex查看,对应内容为chapter6/TestClass,即类的全限定名。
通过逐个字节对照ASCII字符表,我们同样可以得到内容为chapter6/TestClass。
- 获取ASCII字符表:在Linux上执行man ascii,翻页在Tables项可以看到字符表。
- 查找字符:先找横坐标,再找纵坐标,横竖交叉的位置即为字节对应的字符。
例如0x63为c,0x68为h,0x61为a,0x70为p,0x74为t,0x65为e,0x72为r,连起来代表单词chapter。
第3项常量
tag类型:u1
tag字节地址:00000022
tag值:0x07
这个常量属于CONSTANT_Class_info结构,代表一个类或者接口的符号引用。
name_index类型:u2
name_index字节地址:00000023~00000024
name_index值:0x0004
0x0004指向了常量池中的第4项常量。
第4项常量
tag类型:u1
tag字节地址:00000025
tag值:0x01
这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。
length类型:u2
length字节地址:00000026~00000027
length值:0x0010
将0x0010转换为十进制,计算得到16。
bytes类型:u1
bytes字节地址:00000028~00000037(length表明地址范围为16个字节)
bytes值:下方图片浅蓝底对应的所有字节内容
通过WinHex查看,对应内容为java/lang/Object,即类的全限定名。
第5项常量
tag类型:u1
tag字节地址:00000038
tag值:0x01
这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。
length类型:u2
length字节地址:00000039~0000003A
length值:0x0001bytes类型:u1
bytes字节地址:0000003B(length表明地址范围为1个字节)
bytes值:0x6D
通过WinHex查看,对应内容为实例变量m。
其他常量可以通过类似的方法进行分析,但这样一个个分析确实挺辛苦的。
其实,JDK已经为我们提供了一个Class文件字节码工具:javap,可以让我们较为直观的看到Class文件的字节码内容。
执行命令:javap -verbose TestClass.class,截取常量池部分内容如下:
可以看到,版本号及前5个常量与我们分析的结果是一致的。所以,能用1行代码搞定的事儿,就不要用2行(浪费笔墨)。
常量池最后一个字节:000000D8
访问标志(access_flags)
类型:u2
字节地址:000000D9~000000DA
值:0x0021
查看类或接口访问标志含义表可知,该类的访问标志为ACC_PUBLIC(0x0001)、ACC_SUPER(0x0020)。
另外,通过类的定义public class TestClass,同样可以推断出类的访问标志为ACC_PUBLIC、ACC_SUPER,而ACC_INTERFACE、ACC_ENUM、ACC_FINAL、ACC_ABSTRACT、ACC_ANNOTATION、ACC_SYNTHETIC都可以排除。
所以,access_flags应该为0x0001|0x0020=0x0021,结果与查看字节码相同。
类索引(this_class)
类型:u2
字节地址:000000DB~000000DC
值:0x0001
this_class指向常量池的第1个常量,基于前面的分析可知:
- 第1个常量的类型为Class,Class名称索引指向第2个常量。
- 第2个常量类型为Utf8,对应内容为chapter6/TestClass。
因此,类索引(this_class)指向的类为chapter6/TestClass。
父类索引(super_class)
类型:u2
字节地址:000000DD~000000DE
值:0x0003
同样,super_class指向常量池的第3个常量。
- 第3个常量的类型为Class,Class名称索引指向第4个常量。
- 第4个常量类型为Utf8,对应内容为java/lang/Object。
因此,父类索引(super_class)指向的类为java/lang/Object。
接口计数器(interfaces_count)
类型:u2
字节地址:000000DF~000000E0
值:0x0000
接口计数器值为0,说明该类没有实现任何接口。
接口表(interfaces)
无
类索引(this_class)、父类索引(super_class)和接口索引(interfaces)这三项数据共同确定了当前类以及其继承关系,相关常量池内容如下:
完整地址范围:000000DB~000000E0
字段
字段计数器(fields_count)
类型:u2
字节地址:000000E1~000000E2
值:0x0001
说明当前类有1个字段。
字段表(fields)
访问标志(access_flags)
类型:u2
字节地址:000000E3~000000E4
值:0x0002
对应的访问标志为ACC_PRIVATE。
名称索引(name_index)
类型:u2
字节地址:000000E5~000000E6
值:0x0005
对应常量池中的第5项常量,即字段名为m。
描述符(descriptor_index)
类型:u2
字节地址:000000E7~000000E8
值:0x0006
对应常量池中的第6项常量,值为I,即int类型。
因此,该字段的定义为private int m;
属性计数器(attributes_count)
类型:u2
字节地址:000000E9~000000EA
值:0x0000
说明该字段没有属性信息。
属性表(attributes)
无。
字段完整地址范围:000000E1~000000EA
最后是方法和属性,由于内容复杂度及篇幅原因,我们下篇再续。
参考
《Java虚拟机规范》(Java SE 8版)
《深入理解Java虚拟机 JVM高级特性与最佳实践》
转载请注明来源:http://zhanjia.iteye.com/blog/2430255
个人公众号
二进制之路
相关推荐
Class文件是Java编译器将源代码编译后的结果,包含了类的结构信息、方法定义、常量池等关键数据。理解并能解析Class文件,对于进行JVM优化、字节码分析、动态代理、插桩等高级技术至关重要。 首先,Class文件是以二...
总的来说,Java Class文件解析是深入理解JVM工作原理和Java程序运行机制的关键,它不仅涉及到编程实践,也是软件调试、性能优化和安全分析的重要手段。通过学习这一领域的知识,开发者能够更好地驾驭Java平台,提升...
- ProGuard和R8是常见的代码混淆工具,它们会改变class文件结构,增加逆向工程难度。 4. **代码优化**: - 通过分析class文件,可以了解方法调用频率、变量使用情况,从而进行针对性优化。 - 使用ProGuard/R8...
本项目“基于Go的Java Class文件解析工具”旨在利用Go语言开发一个工具,用于解析和理解这些二进制文件,帮助开发者更好地分析和理解Java程序的底层结构。 Go语言是一种静态类型的、编译型的、垃圾回收的语言,具有...
通过以上分析,我们可以看到,class文件解析是理解Java运行机制的关键一环,而《深入理解Java虚拟机》一书为我们提供了宝贵的理论基础和实践指导。结合样例数据,读者可以进一步探索和掌握Java虚拟机的内部运作。
1. **Java类文件结构**:首先,了解Java类文件的内部结构至关重要。每个Java类文件都是以`.class`后缀的二进制文件,它由魔数、版本号、常量池、访问标志、类索引、父类索引、接口索引集合、字段表集合、方法表集合...
1. 创建`ClassWriter`实例,并设定类的访问标志、全限定名和父类信息(通常是`java.lang.Object`)。 2. 定义代理类的字段,如果需要的话。 3. 为每个要拦截的方法创建一个`MethodVisitor`。在`visitMethod`方法中...
Java 类文件结构是Java虚拟机(JVM)执行的基础,它包含了构成Java程序的所有必要信息。Class文件是一种二进制...理解Class文件的结构对于深入学习Java虚拟机的工作原理、优化代码以及进行反编译分析等都有重要意义。
Java编写的网页版魔方游戏,编译后生成.class文件,然后用HTML去调用,不过运行时候需要你的浏览器安装有运行Class的插件。Java源代码实现部分,比较有意思,也具参考性。像坐标控制、旋转矩阵、定时器、生成图像...
例如,将常量池、字段表和方法表等结构抽象为树节点,通过递归遍历这些节点来处理和分析Class文件内容。这种实现方式有助于理解复杂的类结构,并方便进行修改和优化。 在Java开发中,理解Class文件的结构对于深入...
### 安卓反编译dex文件格式实例分析 #### 第一部分:创造一个可供分析的Hello.dex ##### 测试环境 为了进行本次实验,我们需要搭建一个可靠的测试环境。本实验使用了以下配置: - **操作系统**: Ubuntu 12.04 64...
本压缩包文件提供了两个示例项目,分别展示了JDK动态代理和CGLib动态代理的实现,帮助我们理解这两种技术的工作原理以及它们生成的class文件结构。 首先,我们来详细了解JDK动态代理。JDK动态代理基于Java的接口...
#### 一、Java与JVM中的Class文件加载机制概述 Java作为一种动态性极强的解释型编程语言,在程序运行时,Java虚拟机(JVM)负责将编译生成的`.class`文件加载到内存中进行执行。在Java环境中,每个类(Class)以及...
另外,` jclasslib`是一款可视化的字节码查看器,它提供了更直观的方式查看和分析.class文件,包括类结构、常量池、字段和方法的详细信息。使用这样的工具可以帮助我们更好地理解JVM的内部工作原理。 此外,学习...
6. **代码生成**:最后,将AST转换回字节码,即.class文件,这一步由Java编译器完成。字节码是Java虚拟机(JVM)能执行的语言。 在这个实例程序中,可能包含以下组件: - 一个词法分析器,用于将源代码分割成标记。 ...
Java字节码是Java程序编译后的产物,它以`.class`文件的形式存在,是Java虚拟机(JVM)能够理解和执行的二进制代码。本文将深入解析Java字节码的格式,帮助你理解其背后的运行机制。 1. **Java字节码结构** Java...
### Java程序结构与示例分析 #### 一、概述 Java是一种广泛使用的面向对象编程语言,具有简单性、面向对象性、健壮性、安全性、平台独立性等优点。Java程序的基本单位是类(Class),类由方法和成员变量组成。本文...
它包含了编译后的.class文件和其他资源,用户可以通过java -jar命令直接运行。 7. **安全性**:文件传输可能涉及安全问题,如数据的加密和身份验证。Java提供了SSL/TLS协议支持,可以使用SSLSocket和...