Java类文件结构

时间:2021-12-15 13:54:32

 

注:刚读完《深入理解Java虚拟机》的类文件这一章,梳理一下思路。

在此之前我只知道源文件.java需要先进行javac编译成为.class文件。那么.class这个类文件是如何保存的呢?看一遍书都是浑浑噩噩搞不太明白,看了三遍大概知道是怎么存储了。

原来就是用的表和无符号数,u1,u2,u4,u8, 这里u应该是unsigned无符号的意思,1、2、4、8分别代表所占的字节,作用是用来描述数字啊,索引引用啊,数量值或者字符串之类的。就是这两个类型构成了java的类文件。

当然不会是乱存放的,要找一个规定好的顺序来存放。

Java类文件结构

 

1.魔数(magic)

  magic number是一个u4类型的数,作用仅仅是标示这个文件是否能别虚拟机所接受。 看它的具体值:oxCAFFBABE 咖啡宝贝? 哈哈哈

2.版本号(minor_version 和major_version)

  第2、3个表示的是这个类文件的版本好,是两个u2,minor version此版本号,major version主版本号java1.1是从45开始的。每一个大的版本响应的+1。 jvm可以向下兼容,但是不允许低版本运行高版本编译的类文件,否则会报错:Unsupported major version 50(50是java1.7的版本)。

3.常量池(constant_pool_count 和 constant_pool)

  这个常量池很重要,可以理解成class文件中的资源仓库,它是class文件中与其他项目关联最多的数据类型,也是占用最大内存的类型。  上面我们说了,java的类文件是由无符号数和表组成的。constant_pool_count常量计数器,值得提的一点是它是从1开始计数和我们的习惯有所差别(平时都是由0开始计数)其中的原因是0表示“不存在任何一个常量池项目”,常量池一共有21一个项常量。

  可以分为两个大类:字面量和符号引用。   第一个字面量相当于在java中常说的java的常量,而符号引用又包含了3类:a)类和接口的权限名 b)字段名称和描述符 c)方法名称和描述符。

  常量池中的每一项又对应着一个表

Java类文件结构

 

  这14个类型,就对应着14张表,每个类型都有自己相应的数据结构。

 

4.访问标志(access_lags)

  常量池结束够紧接着就是u2的访问标志,这个标志用于识别一些类或者接口的访问信息,比如(ACC_PUBLIC是不是一个public类型啊,ACC_INTERFACE 是不是一个接口啊)等等

5.类索引、父类索引与接口索引集合(this_class、super_class、interface_count、interfaces)

  这里需要注意的是与上面的不同,它是一个集合。试想一下我们写的类只能有一个父类(Object除外)和多个接口,如何描述他们? 就是通过这个三个数据来确定这个类的继承关系。注意的是这三个数据都需要使用它的权限名。 那么interface_count是干什么的呢?  在class文件中,所有可能包含多个值的数据都有一个相应的count计数器。用来作为找到这个数据的入口。

6.字段表集合(fields_count、fields)

  上面说了,可能包含多个数据的都有一个相应的count计数器。所以这个fields_cont的作用也是提供入口。 files是一个表的类型,包含其相应的字段类型。 需要注意的是这里有一个简单名和权限名的区别。比如sun.java.tools.mytools这样一个类用权限名表示:sun/java/tools/mytools这样把 ‘.’换成‘/’。  那么简单名是指没有类型和参数修饰的方法或者字段。比如方法:void index(char[]source,int count)用简单名来表示这是:[CIV。 具体的类型表示方法百度一下吧。

7.方法表集合(methods_count 、methods)

  和字段表集合非常的类似,区别在methods这张表中的字段一些不太一样。

8.属性表集合

  属性表集合中包含了大量的数据信息,上面的所有类型都有十分严格顺序,长度,大小。而属性表中就没有那么严格了,我们编写的最多的Code就存放在属性表集合中的CODE表中,一共有21项比如还包含:Exception表等等。具体的每一个项都是有意义的,有点多简单的介绍一下主要的:

  1) Code 属性

    Java方法体里面的代码经过Javac编译之后,最终变为字节码指令存储在Code属性内,Code属性出现在方法表的属性集合中,但在接口或抽象类中就不存在Code属性

   2)Exception属性

    列举出方法中可能抛出的受查异常

  3)LineNumberTable属性

    描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。主要是如果抛出异常时,编译器会显示行号,就是这个属性的作用

  4)LocalVariableTable属性

    描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系。用处在于当别人使用这个方法是能够显示出方法定义的参数名

  5)SourseFile属性

    记录生成这个Class文件的源码文件名称

    抛出异常时能够显示错误代码所属的文件名

  6)ConstantValue属性

    通知虚拟机自动为静态变量赋值,只有被static字符修饰的变量(类变量)才可以有这项属性

  7)InnerClass属性

    用于记录内部类与宿主类之间的关联

  8、9)Deprecated和Synthetic属性

    这两个都是标志类型的布尔属性

    Deprecated表示不再推荐使用,注解表示为@deprecated

    Synthetic表示此字段或方法是由编译器自行添加的