转载

深入理解Java虚拟机笔记---字段表集合

字段表(field_info)用于描述接口或类中声明的变量。字段(field)包括了类级变量或实例变量,但不包括方法内部声明的变量。描述一个字段的信息有:字段的作用域(public,private,protected修饰符),是类级变量还是实例级变量(static修饰符),可变性(final),并发可见性(volatile修饰符,是否强制从主内存读写),是否可序列化(transient修饰符),字段数据类型(基本数据类型,对象,数组),字段名称。这些信息中,各个修改符都是布尔值,要么有某个修饰符,要么没有,很适合使用标志位来表示。而字段叫什么名字,字段被定义为什么数据类型,这些都是无法固定的,只能引用常量池中的常量来描述。下面是字段表的最终格式。

file

字段修饰符放在access_flags项目中,它与类的access_flags项目是非常相似的,都是一个u2的数据类型,其中可以设置的标志位和含义如下表:

file

跟随access_flags标志的是两项索引值:name_index和descriptor_index。它们都是对常量池的引用,分别代表着字段的简单名称及字段的描述符。现在需要解释一下“简单名称”,“描述符”及前面出现过多次的“全限定名”这三种特殊字符串的概念。
全限制名称和简单名称很好理解,如“org/fenixsoft/clazz/TestClass"就是一个类全限制名,仅仅是把类名中的”.“替换成了”/“而已,为了使连续的多个全限定名之间不产生混淆,在使用时最后一般会加上一个“;”号表示全限定名结束。简单名称就是指没有类型和参数修饰的方法或字段名称。
相对于全限定名和简单名称来说,方法和字段的描述符就要复杂一些。描述符的作用是来用描述字段的数据类型,方法的参数列表(包括数量,类型及顺序)和返回值。根据描述符规则,基本数据类型(byte,char,double,float,int,long,short,boolean)及代表无返回值的void类型都使用一个大写字符来表示,而对象类型则用字符L加对象全限定名来表示,如下图:

file

对于数组类型,每一维度使用一个前置的 字符来描述,如一定义为java.lang.String[][]类型的二维数组,将被记录为:“[[java/lang/String;”,一个整型数组“int[]”将被记录为“[I”。
用描述符来描述方法时,按照先参数列表,后返回值的顺序描述,参数列表按照参数的严格顺序在一组小括号“()”之内。如方法void int()描述符为:”()V“,方法java.lang.String toString()描述符为:“()java/lang/String;”
字段表都包含的固定数据项目到descriptor_index为止就结束了,但是在descriptor_index之后跟随着一个属性表集合用于存储一些额外的信息,字段都可以在属性表中描述0至多项额外的信息。字段表集合中不会列出超类或父接口中继承而来的字段,但有可能列表出原来Java代码中不存在的字段,譬如在内部类中为了保持对外部类的访问性,会自动添加指向外部类实例的字段。另外,在Java语言中字段是无法重载的,两个字段的数据类型,修饰符不管是否相同,都必须使用不一样的名称,但是对于字段码来讲,如果两个字段的描述符不一致,那字段重名就是合法的。

正文到此结束
本文目录