美文网首页java
深入理解Class文件-1

深入理解Class文件-1

作者: 左手落花 | 来源:发表于2020-03-04 17:23 被阅读0次

    什么是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文件结构的解析。

    相关文章

      网友评论

        本文标题:深入理解Class文件-1

        本文链接:https://www.haomeiwen.com/subject/jqcblhtx.html