1.对class文件解析
1.1解析过程
新建类TestClass.java 通过javap -v 指令查看class文件结构如下图:
查看常量池结构表对如下进行分析:
如图
第一步:invokespecial 对应常量池#1;
第二步:在常量池中找到#1常量 #1 = Methodref #4.#22 // java/lang/Thread."<init>":()V
Methodref数据结构为:
#4 u2(字节) 指向声明方法的类描写叙述符CONSTANT_Class_info的索引项
#22 u2(字节) 指向名称及类型描写叙述符CONSTANT_NameAndType_info的索引项
第三步:找#4常量对应#25常量 #25 常量对应 #25 = Utf8 java/lang/Thread
第四步:#22常量对应 #22 = NameAndType #7:#8
NameAndType数据结构为:
#7 u2(字节) 指向该字段或方法名称常量项的索引
#8 u2(字节) 指向该字段或方法描写叙述符常量项的索引
第五步:#7对应 #7 = Utf8 <init>
第六步:#8对应 #8 = Utf8 ()V(返回类型)
解析结果: V java/lang/Thread.<init>()
1.2init与clinit分析
1.init:实例化初始化方法
几种放到init中的情况:
1.调用new初始化对象的时候;
2.调用反射的时候newInstance();
3.调用clone方法的时候;
4.ObjectInputstream.getObject序列化的时候;
2.clinit:类和接口的初始化
所有的类变量初始化语句和静态初始化语句都被java编译器搜集到一起,放到clinit;
2.访问标志
紧接着常量池之后的两个字节代表访问标志(access_flags),用于识别一些类或者接口层次的访问信息,包括:这个class是类还是接口是否为public类型、是否为abstract类型、类是否申明为final等.
标志位及其含义如下表:
标志名称 | 值 | 说明 |
ACC_PUBLIC | 0X0001 | public类型 |
ACC_FINAL | 0X0010 | 申明为final,只有类可以设置 |
ACC_SUPER | 0X0020 | 使用invokespecial字节码指令的新语意,invokespecial指令的语意在JDK1.0.2发生过改变,为了区别这条指令使用哪种语意,JDK1.0.2之后编译出来的类都为真 |
ACC_INTERFACE | 0X0200 | 接口 |
ACC_ABSTRACT | 0X0400 | abstract类型,对于接口或者抽象类来说,此标志值为真,其他类型为假 |
ACC_SYNTHETIC | 0X1000 | 这个类并非由用户代码产生 |
ACC_ANNOTATION | 0X2000 | 注释 |
ACC_ENUM | 0X4000 | 枚举 |
3.类索引、父类索引与接口索引集合
访问标志之后顺序排列类索引(this)、 父类索引(super)、接口索引集合(interfaces)。
class文件由这三项来确定这个类的集成关系。
类索引和父类索引都是u2类型的数据。
接口索引集合入口第一项是u2类型的接口计数器(interfaces_count)表示索引表的容量(即实现了几个接口)。如果该类没有实现任何接口,则计数器值为0,后面的接口索引不再占用任何字节。