全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Java class文件格式之属性详解_动力节点java学院整理

Code属性

code属性是方法的一个最重要的属性。 因为它里面存放的是方法的字节码指令, 除此之外还存放了和操作数栈,局部变量相关的信息。 所有不是抽象的方法, 都必须在method_info中的attributes中有一个Code属性。下面是Code属性的结构, 为了更直观的展示Code属性和method_info的包含关系, 特意画出了method_info:

下面依次介绍code属性中的各个部分。

attribute_name_index指向常量池中的一个CONSTANT_Utf8_info , 这个CONSTANT_Utf8_info 中存放的是当前属性的名字 “Code” 。

attribute_length给出了当前Code属性的长度(不包括前六字节)。

max_stack 指定当前方法被执行引擎执行的时候, 在栈帧中需要分配的操作数栈的大小。

max_locals指定当前方法被执行引擎执行的时候, 在栈帧中需要分配的局部表量表的大小。注意, 这个数字并不是局部变量的个数, 因为根据局部变量的作用域不同, 在执行到一个局部变量以外时, 下一个局部变量可以重用上一个局部变量的空间(每个局部变量在局部变量表中占用一个或两个Slot)。 方法中的局部变量包括方法的参数, 方法的默认参数this, 方法体中定义的变量, catch语句中的异常对象。 关于执行引擎的相关内容会在后面的博客中讲到。

code_length指定该方法的字节码的长度, class文件中每条字节码占一个字节。

code存放字节码指令本身, 它的长度是code_length个字节。

exception_table_length 指定异常表的大小

exception_table就是所谓的异常表, 它是对方法体中try-catch_finally的描述。 exception_table可以看做是一个数组, 每个数组项是一个exception_info结构, 一般来说每个catch块对应一个exception_info,编译器也可能会为当前方法生成一些exception_info。 exception_info的结构如下(为了直观的显示exception_info, exception_table和Code属性的关系, 画出了Code属性,的话读者就会更清楚各个数据项之间的位置关系和包含关系):

下面讲解exception_info中的各个字段的意思。

start_pc是从字节码(Code属性中的code部分)起始处到当前异常处理器起始处的偏移量。

end_pc是从字节码起始处到当前异常处理器末尾的偏移量。

handler_pc是指当前异常处理器用来处理异常(即catch块)的第一条指令相对于字节码开始处的偏移量。

catch_type是一个常量池索引, 指向常量池中的一个CONSTANT_Class_info数据项, 该数据项描述了catch块中的异常的类型信息。这个类型必须是java.lang.Throwable的或其子类。

所以可以总结, 一个异常处理器(exception_info)的意思是: 如果偏移量从start_pc到end_pc之间的字节码出现了catch_type描述的类型的异常, 那么就跳转到偏移量为handler_pc的字节码处去执行。如果catch_type为0, 就代表不引用任何常量池项(再回顾一下, 常量池中的项是从1开始计的), 那么这个exception_info用于实现finally子句。

我们一直在介绍Code属性, 只不过刚才进行了一个小插曲, 介绍了Code属性中的exception_table中的exception_info的详细信息。 下面我们继续介绍Code 属性中的其他信息, 希望读者不要被绕晕了 : )

attributes_count 表示当前Code 属性中存在的其他属性的个数。 现在我们知道, class中的属性, 不仅会出现在顶层的class中, 会存在field_info中, 会存在method_info中, 甚至还会出现在属性中。 

attributes可以看做是一个数组, 里面存放了Code属性中的其他属性。 Code 属性中可以出现的其他属性有LineNumberTable和LocalVariableTable 。 这两个属性会在下面介绍。

LineNumberTable属性

LineNumberTable属性存在于Code属性中, 它建立了字节码偏移量到源代码行号之间的联系。 这个属性是可选的, 编译器可以选择不生成该属性。下面是该属性的结构(同样给出了全局的位置关系,LineNumberTable在图的右下角部分):

由于这个属性并不是重点, 我们在此简单的讲述。 

每个LineNumberTable中的line_number_table部分, 可以看做是一个数组, 数组的每项是一个line_number_info , 每个line_number_info 结构描述了一条字节码和源码行号的对应关系。 其中start_pc是这个line_number_info 描述的字节码指令的偏移量, line_number是这个line_number_info 描述的字节码指令对应的源码中的行号。可以看出, 方法中的每条字节码都对应一个line_number_info , 这些line_number_info 中的line_number可以指向相同的行号, 因为一行源码可以编译出多条字节码。

LocalVariableTable属性 

LocalVariableTable 属性建立了方法中的局部变量与源代码中的局部变量之间的对应关系。 这个属性存在于Code属性中。 这个属性是可选的, 编译器可以选择不生成这个属性。该属性的结构如下:(同样给出了全局的位置关系图,LocalVariableTable 在该图的右下角 )

由于这个属性相对不那么重要, 这里只是大概讲解一下。

每个LocalVariableTable 的local_variable_table部分可以看做是一个数组, 每个数组项是一个叫做local_variable_info的结构, 该结构描述了某个局部变量的变量名和描述符, 还有和源代码的对应关系。下面讲解local_variable_info的各个部分:

start_pc是当前local_variable_info所对应的局部变量的作用域的起始字节码偏移量;

length是当前local_variable_info所对应的局部变量的作用域的大小。 也就是从字节码偏移量start_pc 到start_pc+length就是当前局部变量的作用域范围;

name_index指向常量池中的一个CONSTANT_Utf8_info, 该CONSTANT_Utf8_info描述了当前局部变量的变量名;

descriptor_index指向常量池中的一个CONSTANT_Utf8_info, 该CONSTANT_Utf8_info描述了当前局部变量的描述符;

index描述了在该方法被执行时,当前局部变量在栈帧中局部变量表中的位置。 

由此可知, 方法中的每个局部变量都会对应一个local_variable_info 。 

Exceptions属性

首先需要说明, Exceptions属性不是存在于Code属性中的, 它存在于method_info中的attributes中。 和Code属性是平级的。 这个属性描述的是方法声明的可能会抛出的异常, 也就是方法定义后面的throws声明的异常列表, 请不要和上面提到的异常处理器混淆。 异常处理器描述了方法的字节码如何处理异常, 而Exceptions属性描述方法可能会抛出哪些以异常。下面讲解Exceptions属性的结构(左下角为Exceptions属性):

下面讲解Exceptions属性中的信息。 

attribute_name_index和attribute_length就不多说了, 和其他属性是一样的。 

number_of_exceptions是该方法要抛出的异常的个数。 

exceptions_index_table可以看做一个数组, 这个数组中的每一项占两个字节, 这两个字节是对常量池的索引, 它指向一个常量池中的CONSTANT_Class_info。 这个CONSTANT_Class_info描述了一个被抛出的异常的类型。 

总结

到此为止, 和方法相关的属性就介绍完了。 这篇博客讲解的内容相对比较复杂。 下面以一个实例进行验证, 实例代码:

package com.bjpowernode.test; 
public class Test { 
  public void test() throws Exception{ 
    int localVar = 0; 
    try{ 
      Class.forName("com.bjpowernode.test.Person"); 
    }catch(ClassNotFoundException e){ 
      throw e; 
    }finally{ 
      System.out.println(localVar); 
    } 
  } 
}

反编译后的test方法部分(省略了常量池等信息):

public void test() throws java.lang.Exception; 
 flags: ACC_PUBLIC 
 Exceptions: 
  throws java.lang.Exception 
 Code: 
  stack=2, locals=4, args_size=1 
    0: iconst_0 
    1: istore_1 
    2: ldc      #18         // String com.bjpowernode.test.Person 
    4: invokestatic #20         // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class; 
    7: pop 
    8: goto     24 
   11: astore_2 
   12: aload_2 
   13: athrow 
   14: astore_3 
   15: getstatic   #26         // Field java/lang/System.out:Ljava/io/PrintStream; 
   18: iload_1 
   19: invokevirtual #32         // Method java/io/PrintStream.println:(I)V 
   22: aload_3 
   23: athrow 
   24: getstatic   #26         // Field java/lang/System.out:Ljava/io/PrintStream; 
   27: iload_1 
   28: invokevirtual #32         // Method java/io/PrintStream.println:(I)V 
   31: return 
  Exception table: 
    from  to target type 
      2   8  11  Class java/lang/ClassNotFoundException 
      2  14  14  any 
  LineNumberTable: 
   line 7: 0 
   line 11: 2 
   line 13: 8 
   line 15: 12 
   line 16: 14 
   line 17: 15 
   line 18: 22 
   line 17: 24 
   line 20: 31 
  LocalVariableTable: 
   Start Length Slot Name  Signature 
       0   32   0 this  Lcom/bjpowernode/test/Test; 
       2   30   1 localVar  I 
      12    2   2   e  Ljava/lang/ClassNotFoundException; 

结合上面的讲解和图解, 再分析反编译的结果, 就一目了然了: 所有的结果是一个method_info, method_info开始处是访问标志信息。 然后是method_info的 Exceptions属性 , Exceptions属性属性下面是Code属性, Code属性中又包括字节码, 异常处理器 ,LineNumberTable属性和LocalVariableTable 属性。 

所以会直接或间接的和method_info有联系, 最后给出一张全局图, 这样的话, 读者就比较明确, 一个完整的方法, 是如何在class文件中描述的,由于考虑到复杂性, 这些属性或其他数据项中, 对常量池的引用均未画出:


# java  # class文件格式  # Java Class 解析器实现方法示例  # java动态添加外部jar包到classpath的实例详解  # Java 使用getClass().getResourceAsStream()方法获取资源  # java.lang.NoClassDefFoundError错误解决办法  # Java class文件格式之访问标志信息_动力节点Java学院整理  # Java中Class类的作用与深入理解  # 是一个  # 行号  # 偏移量  # 池中  # 的是  # 是从  # 出了  # 抛出  # 画出  # 源代码  # 出现在  # 会在  # 量表  # 这两个  # 可选  # 可以选择  # 每条  # 建立了  # 所对应  # 反编译 


相关文章: 网页设计与网站制作内容,怎样注册网站?  零基础网站服务器架设实战:轻量应用与域名解析配置指南  如何通过山东自助建站平台快速注册域名?  5种Android数据存储方式汇总  ppt在线制作免费网站推荐,有什么下载免费的ppt模板网站?  已有域名和空间如何快速搭建网站?  建站主机系统SEO优化与智能配置核心关键词操作指南  定制建站哪家更专业可靠?推荐榜单揭晓  网站好制作吗知乎,网站开发好学吗?有什么技巧?  专业公司网站制作公司,用什么语言做企业网站比较好?  孙琪峥织梦建站教程如何优化数据库安全?  上海网站制作网站建设公司,建筑电工证网上查询系统入口?  ,网页ppt怎么弄成自己的ppt?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  如何在香港服务器上快速搭建免备案网站?  免费网站制作模板下载,除了易企秀之外还有什么H5平台可以制作H5长页面,最好是免费的?  如何在新浪SAE免费搭建个人博客?  重庆市网站制作公司,重庆招聘网站哪个好?  如何在万网自助建站平台快速创建网站?  如何通过二级域名建站提升品牌影响力?  建站之星在线客服如何快速接入解答?  常州自助建站:操作简便模板丰富,企业个人快速搭建网站  建站之星导航菜单设置与功能模块配置全攻略  宠物网站制作html代码,有没有专门介绍宠物如何养的网站啊?  如何通过西部数码建站助手快速创建专业网站?  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  如何通过宝塔面板实现本地网站访问?  建站之星CMS建站配置指南:模板选择与SEO优化技巧  学校建站服务器如何选型才能满足性能需求?  C#如何在一个XML文件中查找并替换文本内容  湖北网站制作公司有哪些,湖北清能集团官网?  猪八戒网站制作视频,开发一个猪八戒网站,大约需要多少?或者自己请程序员,需要什么程序员,多少程序员能完成?  太平洋网站制作公司,网络用语太平洋是什么意思?  Thinkphp 中 distinct 的用法解析  Python路径拼接规范_跨平台处理说明【指导】  定制建站模板如何实现SEO优化与智能系统配置?18字教程  c# 在ASP.NET Core中管理和取消后台任务  如何在服务器上三步完成建站并提升流量?  百度网页制作网站有哪些,谁能告诉我百度网站是怎么联系?  最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?  建站之星官网登录失败?如何快速解决?  如何在腾讯云服务器上快速搭建个人网站?  如何用腾讯建站主机快速创建免费网站?  如何在Windows虚拟主机上快速搭建网站?  如何零基础在云服务器搭建WordPress站点?  网站海报制作教学视频教程,有什么免费的高清可商用图片网站,用于海报设计?  北京网站制作网页,网站升级改版需要多久?  用v-html解决Vue.js渲染中html标签不被解析的问题  高端网站建设与定制开发一站式解决方案 中企动力 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。