java--迭代(三)foreach解析与字节码

foreach循环也叫增强型的for循环,他是JDK 5.0的新特性(其他特性例如泛型等)

使用方法如下:

for(type element:array){
  ....//coding here      
}

 

其中关于foreach的优势与局限性在迭代(二)文章中都有指出,并且在上一篇文章提出了关于foreach如何具体实现的问题。

我们通过反编译.class文件(语法为:javap -verbose xxxx.class),得到了如下内容:

其实反编译后的信息很多,但是我只截取了最重要的两部分。至于这两部分分别代表什么,我们先来了解java的字节码怎么读取。当我讲述完成的时候,相信也是能够读懂上面信息的时候。

 

首先我们打开.class文件:显示如下:

 

很清晰的看到是一连串的十六进制组成,这就是汇编形成的字节码,接下来我们对如何解读字节码进行进一步的分析:

 

首先,我们来看一副图:

这幅图就是字节码的结构图,组成部分就分别是这么几个,我将分别进行阐述;

 

1)魔数(Magic Number)

四个字节的魔数,从我给出的.class文件看出,开头的四个字节是cafebabe,当然这是十六进制的数,但是为什么是cafebabe。看看java的图标吧:

 

 

2)版本号:

版本号四个字节,前四个为次版本号,后四个为主版本号,在此,值为0x0000 0034,解析出来就是次版本号为0,主版本号为52;那么,从反编译出来的第一幅图可以看到:

这就是反编译出来的版本号,与我们分析的一致;

至此,前八个字节很简单就被我们分析出来了。

 

3)常量池

接着就是常量池入口。

常量池是class文件中的资源仓库,主要包括两大类:字面量和符号引用。字面量如文本字符串,java申明中为final的值,而符号引用入类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符。 具体怎么实现在内存内存中,则是虚拟机的工作,我们这里还是不要深入比较好。

在进行常量池分析的时候,我们先了解常量池类型表:

 

 

上面描述了11中数据类型的结构,但是jdk1.7后又增加了三种,分别是(CONSTANT_MethodHandle_info,CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)算起来一共是14中,接下来按照demo码对他们进行解答:

0x0048:这是紧接着版本号的,因为常量池的数量不一定,所以我们在入口的时候需要定义一个u2类型的数据来记录到底有多少个常量池,该十六进制表示有71个常量池,这里要注意:该十六进制转换数值为72,但是实际只有71个常量池!! 缩影范围为1-71,第0项被设计者规定空留出来了,这是.class文件格式所规定的。

所以我们接下来要翻译71个常量池。(不可能的,我举例子出来能够引用就可以了):

 

#1: 0x07:tag值为7:class-info,一个U2类型缩影为:0x0002,即#2;

#2:0x01:tag值为1:utf-8info,长度:0x0019:byte长度其实就是这个描述的具体内容,是从一个字节大小扩展出去的。应该是25个字节(0x0019)。还记得我们使用16进制打开的.class文件么?旁边有一串字符,其中包含乱码,中间的某些字符串和16进制的值时一一对应的,采用的asc码。所以,这一段字符的值和16进制对应关系如截图所示:

当然长度只有25字节,所以在25字节过后,是下一个常量池信息了!也就是在07及其以后的数值已经是下一个常量池了。

 

上面两个例子其实就可以很好的解释了,我这个例子的常量池有点长,我这里给出另外一位博主的网站地址,他所举出的例子是很详细的。http://www.importnew.com/24088.html。

我们可以看到,我们自己分析的结果其实就是反编译出来的结果的第一部分。

4)Access_Flag访问标志:

访问标志信息包括这个.class文件是类还是接口,是不是public,是不是abstract,如果是类是否被声明成final:

下面给出这个标志表格:

而我们在给出的.class文件中会发现,此处的标志信息为0x0021。这其实是很简单,0x0020与0x0001的并集。即包含了两个标志信息,这里汇编器自动将这个类归类为超类。

 

5)类索引

类索引引用与确定类的全限定名

0x0001表示引用第一个索引,就是:#1.#2.iteretorTest/TestIterator.

6)超类索引

与类索引一致,确定超类的全限定名

0x0003表示引用第三个索引,就是:#3.#4. java/lang/Object;

7)接口索引

可以看到接口索引为2+n个字节,而我们的测试程序没有应用接口,所以我们的前两个字节是0x0000。那么,也不存在n的情况。但是如果有接口,这个时候后面直接跟着接口的索引。

8)字段表集合

字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量以及实例变量,但是不包括方法内部声明的局部变量。

而且,字段表也是2+n个字节,在本文的例子中,我们没有变量,所以在.class文件中,这里为0x0000;

但是,实际上,很多情况下都会涉及到包含变量。

这个时候,我们给出字段表集合,来对这段字段进行分析;

同样,用上面给出博主的文章中的例子可以在此分析一下。

 

下面就是方法,我们将在下一篇文章中写出,方法的解析就会相交前面的复杂很多,其中某些字符的含义需要单独解释,例如<init>,()V,我将会用一个单独的篇章进行方法的字节码解析。

 

转载于:https://www.cnblogs.com/DSNFZ/articles/7599627.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值