每个类基本上都会有一些最基本元素,比如访问标识、父类、字段,那么他们在class文件中是如何存在的呢!
回顾
上一篇文章把class文件的常量池分析完成,在看class文件结构如下图:
访问标识
接下来的结构是access_flags,占用两个字节表示class文件的访问类型。具体值对应的类型如下图:
2个字节虽然能够表达足够大的数,但是访问类型通常都是组合出现,所以如果想要通过2个字节表达多个访问类型的组合,只能使访问类型在16位的二进制中各占一个位置,如上图已经把标志值转成了二进制,可以看到他们各自占用一位,这样不管他们怎么组合,只要知道结果也就能反推出是由那些标志位组合而成,同时表明类型最多只能支持16种。
在看16进制的class文件如下图:
接着上一篇文章继续分析,接下来两个字节表示的是文件的访问标识,值为“00 21”,可以很直接推算0020 | 0001=0021,所以这个类的访问标识符是ACC_SUPER、ACC_PUBLIC,说明这个类是pubilc并且是1.0.2版本以后的。
类索引、父索引、实现接口
根据class文件结构后面4个字节分别表示当前类和父类的索引名称,“00 03 00 04”指向的是上一篇文章分析的常量池中的第3、4项,可以知道结果分别为:“com/dggcc/test/lei/ClassTest”、"java/lang/Object",测试类没有继承任何类默认Object。
紧接着两个字节表示实现的接口数量"00 00"说明没有实现任何接口,没有实现接口的话interface_info结构也就不会存在!
字段
这次换一种方式来表达结构可能能够更好的理解,字段的内部结构如下图:
比如一个属性public final int i;那么access_flags表达public与final,name_index指向常量池的i,descriptor_index指向常量池中表达'int'字符串这个常量项。
由于字段的access_flags与类的access_flags相似,都是通过2个字节来表达多个访问标识符的组合,访问标识符对应如下图:
继续读取源码中的8个字节"00 01 00 02 00 05 00 06",分别表示access_flags=1,即为public,name_index指向常量池第2项上一篇文章查到结果为"com/dggcc/test/lei/ClassTest.var1:I",表示这个变量的全限定名称,I表示他是int型,descriptor_index=5表示指向常量项第5项结果为var1,至此一个字段分析完成!
总结
通过前面的常量池准备,class文件总算开始存储用户代码的信息了,随后开始的是类的一些基本信息,通过两个字节与位运算实现访问标识的多种组合,这种技巧是我们平时可能不会想到的,值得学习!父索引为java/lang/Object也印证了类的默认父类为Object。字段则分别存储了全限定名称与简单名称,但是有个问题是在代码“private int var1=0”后面的0没有提现出来,这个大家可以思考思考!
Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!
领取专属 10元无门槛券
私享最新 技术干货