类索引,父类索引与接口索引集合
类索引(this_class)和父类索引(wuper_class)都是一个u2类型的数据,而接口索引是一组u2类型的数据集合,从这里可以体现出java语言是不允许有多继承的但是可以有多实现。这三项数据确定了这个类的继承关系。类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名。除了java.lang.Object之外,所有的Java类都有父类,因此除了java.lang.Object之外,所有Java类的父类索引都不为0.接口索引集合就是来描述这个类实现了哪些接口,这些接口按照从左到右的循序依次排列在接口索引集合中。
类索引和父类索引用两个u2类型的索引值表示,他们各自指向一个类型为CONSTANT-Class_info的类描述符常量;接口索引集合,入口的第一项是一个u2类型的数据计数器,表示索引表的容量。如果该类没有实现任何接口,则该计数器为0,后面的接口索引表不在占用任何字节。
字段表集合
字段表(field_info)用于描述接口或类中声名的变量。字段包括类级变量和实例级变量,但不包括在方法内部声明的局部变量。
想一想一个字段的描述包括什么?
- 字段的作用域(public,private,protected修饰符)
- 是类级变量还是实例变量(static修饰符)
- 可变性(final)
- 并发可见性(volatile修饰符)
- 可否被序列化(transient修饰符)
- 字段数据类型(基本类型,对象,数组)
- 字段名称
这些信息都是布尔值,要么有某个修饰符,要么没有,很适合使用标志位来表示。而字段叫什么名字,字段被定义成什么数据类型这些都是无法固定的,只能引用常量池中的常量来描述。字段表结构如下
类型 | 名称 | 数量 |
---|---|---|
u2 | access_flags | 1 |
u2 | name_index | 1 |
u2 | descriptor_index | 1 |
u2 | attributes_count | 1 |
attribute_info | attributes | attributes_count |
name_index和descriptor_index 都是对常量池的引用,分别代表着字段的简单名称以及字段和方法的描述符(全限定名和简单名称很好理解:“org/fenixsoft.clazz/TestClass”是这个类的全限定名。简单名称就是指没有类型和参数修饰符的方法或者字段名称) 。
相对于全限定名和简单名称来说,方法和字段的描述符就要父子一些。描述符的作用是用来描述字段的数据,方法的参数列表和返回值。根据描述符规则,基本数据类型(byte,char,double,float,int,龙,short,boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符L加对象的全限定名来表示。
标识字符 | 含义 |
---|---|
B | 基本类型 byte |
C | 基本类型 char |
D | 基本类型 double |
F | 基本类型 float |
I | 基本类型 int |
J | 基本类型 long |
S | 基本类型 short |
Z | 基本类型 boolean |
V | 特殊类型 void |
L | 对象类型 如Ljava/lang/Object |
对于数组类型,每一位度将使用一个前缀“[”字符来表示,如定义一个“java.lang.String[][]”类型的二维数组,将被记录位:“[[Ljava/lang/String;”,一个整形数组“int[]”将被记录为:“[I”.
用描述符来描述方法时,按照先参数列表后含绘制的顺序描述,参数泪飙按照参数的严格顺序放在一组小括号“()”之内。如方法 void main()的描述符为“()V”,方法java.lang.String toString()的描述符为“()Ljava/lang/String;”。
方法表集合
Class文件存储格式中对方发的描述与对字段的描述几乎采用了完全一致的方式,放发表的结构如同字段表一样。这里就不多说了。
在Java中,要重载一个方法,除了要与原方法具有相同的简单名称之外,还要求必须拥有一个与原方法不同的特征签名,特征签名就是一个方法中各个参数在常量池中的字段符号引用的集合,也就是因为返回值不会包含在特征签名中,因此java中是无法依靠返回值的不同来对一个已有的方法进行重载的。
属性表集合
属性表:在Class文件,字段表,方法表都可以携带自己的属性表集合,用以描述默写场景专有的信息。java虚拟机规范中在javaSE7中预定义了21项。如下表:
属性名称 | 使用位置 | 含义 |
---|---|---|
Code | 方法表 | Java代码编译成的字节码指令 |
ConstantValue | 字段表 | final关键字定义的常量值 |
Deprecated | 类,放发表,字段表 | 被声明为deprecated的方法和字段 |
Exceptions | 方法表 | 方法抛出的异常 |
EnclosingMethod | 类文件 | 仅当一个类为局部类或者内名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法 |
InnerClasses | 类文件 | 内部类列表 |
LineNumberTable | Code属性 | java源码的行号与字节码指令的对应关系 |
LocalVariableTable | Code属性 | 方法的局部变量的描述 |
StackMapTable | Code属性 | JDK1.6中新增的属性,公信的类型检查验证器检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配 |
Signature | 类,方法表,字段表 | JDK1.5中新增的属性,这个属性用于支持反省的情况下的方法签名 |
SourceFile | 类文件 | 记录源文件名称 |
SourceDebugExtension | 类文件 | JDK1.6中信证的属性,SourceDebugExtension属性用于存储额外的调试信息 |
Synthetic | 类,方法表,字段表 | 标识方法或者字段为编译器自动生成的 |
LocalVariableTypeTable | 类 | JDK1.5中新增的属性,他使用特征签名代替描述符,是为了一如泛型语法之后能描述泛型参数化类型而添加的 |
RuntimeVisibleAnnotations | 类,方法表,字段表 | JDK1.5中新增的属性,为动态注解提供支持。用于指明哪些注解是运行时可见的 |
RuntimeVisibleParameter | 类,方法表,字段表 | JDK1.5中新增的属性,与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法参数 |
RuntimeInvisibleParameterAnnotations | 方法表 | JDK1.5中新增的属性,与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法参数 |
AnnotationDefault | 方法表 | JDK1.5中新增的属性,用于记录注解类元素的默认值 |
BootstrapMethods | 类文件 | JDK1.7中新增的属性,用于保存invokedynamic指令引用的引导方法限定符 |