深入理解Class文件-1

什么是class文件

  Java字节码类文件(.class)是Java编译器编译Java源文件(.java)产生的“目标文件”。它是一种8位字节的二进制流文件。JVM能识别、加载并执行class文件。作为一个Java开发者,要想在技术上有更高的造诣,就需要深入到原理层面去认识代码运行的机制。

了解class文件文件最好的方法就是看jvm的官方文档,这里贴出地址:
jvm7 class文件格式: 参考 https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

class文件的总体结构如下:

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表示4个字节,同理u2表示2个字节,带有XX_info表示一个结构体

1、magic
  在class文件开头的四个字节, 存放着class文件的魔数, 这个魔数是class文件的标志,它是一个固定的值: 0XCAFEBABE 。 也就是说它是判断一个文件是不是class格式的文件的标准, 如果开头四个字节不是0XCAFEBABE, 那么就说明它不是class文件, 不能被JVM识别。

2、minor_version 和 major_version
  之后的四个字节是class文件的次版本号和主版本号。随着Java的发展, class文件的格式也会做相应的变动。 版本号标志着class文件在什么时候, 加入或改变了哪些特性。 举例来说, 不同版本的javac编译器编译的class文件, 版本号可能不同, 而不同版本的JVM能识别的class文件的版本号也可能不同, 一般情况下, 高版本的JVM能识别低版本的javac编译器编译的class文件, 而低版本的JVM不能识别高版本的javac编译器编译的class文件。 如果使用低版本的JVM执行高版本的class文件, JVM会抛出java.lang.UnsupportedClassVersionError 。

3、constant_pool_count、constant_pool
  位于版本号后面的就是常量池相关的数据项。 常量池是class文件中的一项非常重要的数据。 常量池中存放了文字字符串, 常量值, 当前类的类名, 字段名, 方法名, 各个字段和方法的描述符, 对当前类的字段和方法的引用信息, 当前类中对其他类的引用信息等等。
下面的表格是常量池数组里可能的类型表格:

类型 数值 描述
CONSTANT_Utf8_info 1 UTF-8 编码的字符串
CONSTANT_Integer_info 3 整型字面量
CONSTANT_Float_info 4 浮点型字面量
CONSTANT_Long_info 5 长整型字面量
CONSTANT_Double_info 6 双精度浮点型字面量
CONSTANT_Class_info 7 类或接口的符号引用
CONSTANT_String_info 8 字符串类型字面量
CONSTANT_Fieldref_info 9 字段的符号引用
CONSTANT_Methodref_info 10 类中方法的符号引用
CONSTANT_InterfaceMethodref_info 11 接口中方法的符号引用
CONSTANT_NameAndType_info 12 字段或方法的部分符号引用
CONSTANT_MethodHandle_info 15 表示方法句柄
CONSTANT_MethodType_info 16 标识方法类型
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点

4、access_flag
当前类的访问权限

5、this_class
当前类的全局限定名在常量池里的索引

6、super class
当前类的父类的全局限定名在常量池里的索引

7、interfaces 当前类实现的接口列表,包含两部分内容:interfaces_count 和interfaces[interfaces_count]

interfaces_count 指的是当前类实现的接口数目
interfaces[] 是包含interfaces_count个接口的全局限定名的索引的数组

8、fields 当前类的成员列表,包含两部分的内容:fields_count 和 fields[fields_count]

fields_count是类变量和实例变量的字段的数量总和。
fileds[]是包含字段详细信息的列表。

9、methods 当前类的方法列表,包含两部分的内容:methods_count和methods[methods_count]

methods_count是该类或者接口显示定义的方法的数量。
method[]是包含方法信息的一个详细列表。

10、attributes 当前类的attributes列表,包含两部分内容:attributes_count 和 attributes[attributes_count]

class文件的最后一部分是属性,它描述了该类或者接口所定义的一些属性信息。attributes_count指的是attributes列表中包含的attribute_info的数量。
属性可以出现在class文件的很多地方,而不只是出现在attributes列表里。如果是attributes表里的属性,那么它就是对整个class文件所对应的类或者接口的描述;如果出现在fileds的某一项里,那么它就是对该字段额外信息的描述;如果出现在methods的某一项里,那么它就是对该方法额外信息的描述。

上面是对class文件各个字段的一个简单的描述。如果想更好的了解一个文件结构,我们可以动手去解析它。

根据官方文档的描述class文件的前4个字节是固定的,先来看看是否是如此,测试用的java源代码


image.png

打开cmd,输入命令javac TestClassFile.java 编译生成class文件


image.png

我这里用UltraEdit打开TestClassFile.class文件。显示如下:

image.png

用UltraEdit打开后,每一行显示16个字节。可以看到我红色标注的地方就是class文件的头4个字节的魔数,它是以16进制表示的。

我们尝试修改这个值然后运行看看会发生什么。 把头一个字节修改为00


image.png
image.png

可以看到运行报错了。。。JVM说class文件格式错误。

本次Class 文件结构基本了解就到这里,后续会继续更新Class文件结构的解析。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容