其实在整理字段表和方法表的时候有点疑问,字段表不是也能用描述符描述方法吗(详见下面字段表的描述)?那么还需要方法表干什么呢?后来想了半天,我想到了一个可能的答案,不知道准不准确,先记下来,欢迎评论去留言补充。
字段表存储的是类中的字段,这些字段可能是一些类成员变量,也可能是调用的某个其他类的方法,那么这个方法是不是算作字段存储到字段表当中呢?可能是因为这样,暂时想不到其他的可能性了。而方法表是存储的本类的方法,因为方法表中包含可执行的代码。
class类文件的结构
修饰符:用来表示变量的各种信息,比如可见性(作用域,public,private还是protected),实例变量还是类变量(static),可变性(final),共享可见性(volatile),可否被序列化(transient),字段数据类型(基本数据类型,对象,数组),字段名称,见下图。
跟随标识符的是两项索引值,name_index和descriptor_index。他们都是对常量池的引用,分别代表着字段的简单名称引用以及字段和方法的描述符引用。可能指向的都是CONSTANT_Utf8_info
描述符比较复杂,详见下图:
对于数组类型,每一维度将使用一个前置的“[”字符来描述,如一个定义为“java.lang.String[][]”类型的二维数组,将被记录为:“[[Ljava/lang/String;”,一个整型数组“int[]”将被记录为“[I”。
用描述符来描述方法时,按照先参数列表,后返回值的顺序描述,参数列表按照参数的严格顺序放在一组小括号“()”之内。 如方法void inc()的描述符为“()V”,方法
java.lang.String toString()的描述符为“()Ljava/lang/String;”,方法int indexOf(char[]source,int sourceOffset,int sourceCount,char[]target,int targetOffset,int targetCount,int fromIndex)的描述符为“([CII[CIII)I”。
9、方法表:class文件中方法表的存储格式,和字段表的存储格式几乎一致,如下图所示
access_flags也几乎和上面的一样,只不过方法没有volatile和transient关键字修饰,所以只能就知识少了ACC_VOLATILE和ACC_TRANSIENT标志。
方法的代码并不存在方法表中,而是存在下面我们要介绍的名为“Code”的属性表中。
10.属性表:class文件、字段表、方法表都可以携带自己的属性表集合,用于描述某些场景专有的信息,属性表集合的限制有所宽松,不再要求属性的顺序以及长度。对于方法表的预定义属性,java se7已经增加到了21项,分别表示不同的使用位置,比如字段表内final常量的值,比如方法表内的代码等,见下图
对于属性表中的每个属性,一般都由有三个部分组成:属性名称的引用(指向常量池),属性长度,以及第三个部分的信息,第三部分长度对于不同种类的属性有不同的表示,比如Code属性如下:
attribute_name_index:指向CONSTANT_Utf8_info型常量的索引,常量值固定为Code
attribute_length:指示了属性的长度,由于属性名称和长度一共占了6个字节(前两个,也就是这个和上一个),所以属性值的长度固定位整个属性表长度减去6个字节
max_stack:代表了操作数栈的深度的最大值,在方法执行的任意时刻,操作数栈都不会超过这个深度。虚拟机运行的时候需要根据这个来分配栈帧。
max_locals嗲表了局部变量表所需的存储空间
code_length和code用来存储java源程序编译后生成的字节码指令。codelength的长度限制为u2,虽然长度为u4.可能在编译jsp文件时,会把jsp内容以及页面输出归并与一个方法之中,导致编译失败。