电子说
常量池结束后就是这个Class对应的访问标志内容,用u2(两个字节)来表示。
❝访问标志可以有多个,根据多个标志位的或运算来决定最终的access_flags的取值
❞
访问标志之后的是this_class,super_class,interfaces_count,interfaces这些数据。1.this_class:该Class的权限定名。( 「通过访问常量池中的类信息表来定位到类的权限定名」 )2.super_class:父类的全限定名。(由于Java中是 「单继承多实现」 的,所以父类索引只有一个,但是接口可以有多个稍后将),跟上面的寻找过程类似,只不过换了一个常量池的索引,「如果没有显示使用继承的话那么最终引用的是Object类的权限定名,如果明确使用了继承自哪个类那么最终引用到的就是那个类的权限定名」3.interfaces和interfaces_count 刚刚说了Class是可以多实现的,所以
interfaces_count为 「该Class实现接口的数量」 (如果没有任何实现的接口,那么该值为0后面的interfaces将没有数据不占用任何字节);
interfaces为实现接口的对应接口的全限定名
「该表结构用于描述接口/类中声明的变量」 。
变量可以分为类变量(static级别的),实例变量。
❝注意:该部分不包括方法中的局部变量字段,局部变量会有一个单独的局部变量表来存储,下一篇文章讲解。对于Class文件中最外层的字段表中存储的只是类变量和实例变量。
❞
而字段有哪些数据需要表示呢?权限修饰符,字段名称,字段数据类型,类级别还是实例级别(是否有static修饰符),可变性(final),并发可见性(volatile修饰符,强制从主内存读写),是否可以被序列化(transient修饰符)
这个访问标识和前面讲的类的access_flags不一样,这个是字段的访问标识
这两个索引都是在常量池中的索引,对常量池的引用
name_index为 「字段的名称」 descriptor_index为描述符,对应于字段来说是该**「字段的数据类型」**
描述符的含义:
❝对于一维数组来说使用“[”来表示,如果是二位就用两个“[[”。比如类型为String的二维数组(String[][])用描述符来表示就是[[ java.lang.String;一维数组“int[]”就是[I
❞
可以看到描述符后面还有一个属性表集合,该集合是用来**「存储一些额外的信息,可以添加0到多个信息。」**
如果没有额外描述的信息attributes_count就是0,后面没有字节去描述属性表;如果有额外的信息比如将字段声明为final的话,属性表中就会存储一个ConstantValue的属性,这个值指向对应的常量值。(关于这部分内容之后进行详解)
❝该字段表中不会记录父类中或者父接口中继承来的字段,但是有可能出现原本不存在的字段,比如在内部类中添加字段来访问外部类。
❞
❝重载字段:对于Class文件来说刚刚看了,只要描述符不一致,字段名一样也是可以被记录到Class中的而不会引起冲突;但是对于Java语言来说字段是不能重载的,不管描述符一样不一样,「名称必须不一样!!!」
❞
「该表结构用于描述接口/类中声明的变量」
「图例:」
可以看到和上面讲的字段表结构大致是一样的。
这两个索引都是在常量池中的索引,对常量池的引用
name_index为 「方法的名称」 descriptor_index为描述符,对应于方法来说是该 「方法的参数集合和返回值类型」 对应的数据在上面讲字段表的时候已经贴过图,不在说明。
这个里面的属性表中就会有各种各样的表来存储一个方法的额外信息,比如方法体中的代码,局部变量表等等表结构数据类型。(下一篇文章进行详解)
❝和字段表一样如果父类方法没有被子类重写,那么该表中不会记录父类方法的信息的,但是同样可以出现一些编译器添加的方法,比如类构造器clvinit()和实例构造器init()
❞
❝重载方法:名称一样,方法的特征签名不一样。对于Class文件来说方法的特征签名不同(描述符不完全一致)就可以进行重载不会发生冲突;但是对于Java语言来说方法的特征签名中不包括返回值这个条件所以返回值不同不能作为重载的条件 Java代码层面的方法特征签名,Java代码的方法特征签名只包括方法名称、参数顺序及参数类型,而字节码Class的特征签名还包括方法返回值以及受查异常表,请读者根据上下文语境注意区分。
全部0条评论
快来发表一下你的评论吧 !