Java字节码方法表与属性表深度剖析

方法表:

在上一次咱们已经分析到了字段信息了,如下:

紧接着就是方法相关的信息了:

而它展开之后的结构为:

所以往后数2个字节,看一下方法的总数:

3个方法,可咱们只定义了两个方法呀:

因为编译器会为我们生成一个默认的构造方法,所以就3个了,那每个方法的具体信息是啥呢?它是一个method_info类型的,如下:

也就是方法表,当然也有它自己的一个结构,下面来看一下:

  • access_flags:占用两个字节,表示访问标记。
  • name_index:占用两个字节,名字索引,指向的是常量池。
  • descriptor_index:占用两个字节,描述索引,指赂的是常量池。
  • attributes_count:占用两个字节,属性个数,如果为0,则下面的属性表就不显示了。
  • attributes::属性表。

用结构形式来表示:

那按照上面的表先来看第一个方法的访问标记,往后读两个字节:

查看下访问修饰符表,对应于:

表示是一个public的方法,接下来两个字节则表示方法名字索引,走着:

对应常量池:

再往下二个字节则表示描述符索引:

对应常量池:

说明该方法是一个默认构造方法。从javap -verbose中也能对应上:

属性表:

接下来二个字节为属性个数:

表示有一个属性,所以属性表中的个数也为1,而属性表是attribute_info类型,很显然也有它自己的结构,那长啥样呢?

  • attribute_name_index:占2个字节,表示属性名字的索引,指向常量池。
  • attribute_length:占4个字节,表示属性的长度。
  • info[attribute_length]:占1个字节,表示具体的信息。

依照上面的顺序,先数2个字节:

对应常量池:

其实在javap -verbose中也能看到每个方法都有一个Code字样,如下:

Constant pool:#1 = Methodref          #4.#20         // java/lang/Object."<init>":()V#2 = Fieldref           #3.#21         // com/jvm/bytecode/MyTest1.a:I#3 = Class              #22            // com/jvm/bytecode/MyTest1#4 = Class              #23            // java/lang/Object#5 = Utf8               a#6 = Utf8               I#7 = Utf8               <init>#8 = Utf8               ()V#9 = Utf8               Code#10 = Utf8               LineNumberTable#11 = Utf8               LocalVariableTable#12 = Utf8               this#13 = Utf8               Lcom/jvm/bytecode/MyTest1;#14 = Utf8               getA#15 = Utf8               ()I#16 = Utf8               setA#17 = Utf8               (I)V#18 = Utf8               SourceFile#19 = Utf8               MyTest1.java#20 = NameAndType        #7:#8          // "<init>":()V#21 = NameAndType        #5:#6          // a:I#22 = Utf8               com/jvm/bytecode/MyTest1#23 = Utf8               java/lang/Object
{public com.jvm.bytecode.MyTest1();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: aload_05: iconst_16: putfield      #2                  // Field a:I9: returnLineNumberTable:line 3: 0line 4: 4LocalVariableTable:Start  Length  Slot  Name   Signature0      10     0  this   Lcom/jvm/bytecode/MyTest1;public int getA();descriptor: ()Iflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: getfield      #2                  // Field a:I4: ireturnLineNumberTable:line 7: 0LocalVariableTable:Start  Length  Slot  Name   Signature0       5     0  this   Lcom/jvm/bytecode/MyTest1;public void setA(int);descriptor: (I)Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_01: iload_12: putfield      #2                  // Field a:I5: returnLineNumberTable:line 11: 0line 12: 5LocalVariableTable:Start  Length  Slot  Name   Signature0       6     0  this   Lcom/jvm/bytecode/MyTest1;0       6     1     a   I
}
SourceFile: "MyTest1.java"

那它表示啥意思呢?其实是表示方法执行的代码,指的是:

当然啦在字节码文件中不可能是跟源文件中看到的一样,而是通过了一些助记符进行了处理,如下:

这个在未来进行详细学习的,好,继续来分析属性,接下来4个字节表示属性的长度,如下:

说明属性的长度为56,然后最后一个字节表示info信息,也就是code的具体信息,这块是比较复杂的,下面先来了解一些理论:

  • JVM预定义了部分attribute,但是编译器自己也可以实现自己的attribute写入class文件里,供运行时使用。
  • 不同的attribute通过attribute_name_index来区分。

其中JVM预定义的attribute为如下表:

Code结构:

这部分东东是比较多的,这次只先对其结构有个初步了解既可,它的作用是保存该方法的结构,如所对应的字节码:

  • attribute_length表示attribute所包含的字节数,不包含attribute_name_index和attribute_length字段。
  • max_stack表示这个方法运行的任何时刻所能达到的操作数栈的最大深度。
  • max_locals表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量。
  • code_length表法该方法所包含的字节码的字节数以及具体的指令码。
  • 具体的字节码既是该方法被调用时,虚拟机所执行的字节码。
  • exception_table:这里存放的是处理异常的信息。
  • 第一个exception_table表项由start_pc、end_pc、handler_pc、catch_type组成。
  • start_pc和end_pc表示在code数组中的从start_pc到end_pc处(包含start_pc,不包含end_pc)的指令抛出的异常会由这个表项来处理。
  • handler_pc表示处理异常的代码的开始处。catch_type表示会被处理的异常类型,它指向常量池里的一个异常类。当catch_type为0时,表示处理所有的异常。

这么多陌生的字段,直接晕掉,木要着急,先有个大概了解,在未来学习中会吃透它的,好,先来回到字节码中继续分析,其中code中属性的长度为56:

接下来2个字节表示max_stack:

再接下来2个字节表示max_locals:

对应javap -verbose:

接下来4个字节表示code的长度:

code_length=10,而此时发现在javap -verbose中貌似木有找到对应的:

那接下来的分析没有了参照就不知道我们自己分析的对不对了,对于学习效果会大打折扣了,此时就得借助于另外一个工具来参照了,该工具为jclasslib,gitbub地址:https://github.com/ingokegel/jclasslib,它显示的信息就会比javap -verbose要详细很多,访问一下官网:

它包含独立的软件和IntelliJ IDEA插件化的方式,所以都装一下,先下载mac安装包:

 

具体安装就不概述了,装好之后用它来打开我们的字节码文件既可,长这样:

同时可以给IDE装上插件,更加便于分析,如下:

安装好之后,直接就可以在当前打开的java文件中执行这个菜单选项既可:

看到的效果跟独立的软件看到的是一样的,好,下面来用这个新工具来瞅一眼看到的信息:

对比下javap -verbose:

差不多,不过jclasslib工具可以看到JDK的版本,接下来就是常量池:

但实际是只有23个,展开看一下:

对于javap -versbose:

明显要丰富许多,继续往下看:

其中是可以直接点击链到对应的常量池的,如下:

接着就是常量池的信息了:

展开之后,索引都能链接上去,非常之方便:

接着就是接口信息,目前木有接口:

然后就到了字段信息了,目前只有一个字段:

然后再是方法信息,有三个方法:

点击其中一个看一下:

有code信息:

跟javap -versbose是对应上的:

最后是附加信息:

LineNumberTable:这个属性用来表示code数组中的字节码和Java代码行数之间的关系。这个属性可以用来在调试的时候定位代码执行的行数。比如说程序抛异常了,而程序执行的是字节码文件,怎么我们就能看到具体报错在源码中的行数呢,其实就是通过该信息做到的。

而它的结构体为:

跟javap -verbose中是能对应上的:

最后则是类的属性了:

可见jclasslib的结构跟咱们理论上看到的是一模一样的,所以有了它也能让我们在未来学习code这块的结构更加清晰,这是javap -verbose不能达到的。

转载于:https://www.cnblogs.com/webor2006/p/9459681.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最大连续子数组和与JUnit测试

【题目】最大连续子数组和&#xff08;最大子段和&#xff09; 背景 问题&#xff1a; 给定n个整数&#xff08;可能为负数&#xff09;组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]a[i1]…a[j]的子段和的最大值。当所给的整数均为负数时定义子段和为0&#xff0c;依此定义…

笔记本电源适配器为什么总坏_为什么某些交流适配器和电源会发出啸叫声?

笔记本电源适配器为什么总坏Most of the time our AC adapters and power supplies tend to be quiet, but what does it mean when one makes a whining noise? Should you be concerned? Today’s SuperUser Q&A post has the answers to a worried reader’s question…

4412 字符类设备的设备号

一、静态申请字符类设备号 字符类设备函数在文件"include/linux/fs.h"中内核提供了三个函数来注册一组字符设备编号&#xff0c;这三个函数分别是 register_chrdev_region()alloc_chrdev_region()register_chrdev()register_chrdev_region()是提前知道设备的主次设备…

monogdb操作system.*权限

mongodb roles system.roles集合删不掉 当你自定义了特权(角色): db.createRole({role: "dropSystemViewsAnyDatabase",privileges: [{actions: [ "dropCollection" ],resource: { db: "", collection: "system.roles" }}],roles: []}…

如何发现假库存照片(并将合适的人归于属性)

Spammers and other unscrupulous advertisers are always looking for new ways to get you click on their pages. One of the latest tactics is to steal popular and useful stock images—like the kind you sometimes see in news articles—and re-upload them elsewhe…

Mysql Hunter

一、简介自动化实施的过程中&#xff0c;我们通常都面临一个棘手的问题&#xff1a;数据的准备和恢复。即在成功执行一个自动化用例时&#xff0c;我们可能需要一定的数据前提&#xff0c;而为了使得整个前提不至于被其他的用例破坏&#xff0c;以至于我们有时不得不在自动化用…

C6748_UART(5) - UART寄存器

1、FIFO控制寄存器&#xff08;FCR&#xff09;RXFIFTL&#xff1a;接收FIFO中断触发(当FIFO中的数据量刚到达所要求&#xff08;trigger level&#xff09;的时候会产生中断);DMAMODE1:如果FIFO使能的话此位可以使能DMA模式。TXCLR&#xff1a;发送FIFO清除。RXCLR&#xff1a…

如何在Windows 10上限制Wi​​ndows Update的下载带宽

Windows 10’s Fall Creators Update gives you more control of Windows Update’s downloads and uploads. You can now set a download bandwidth limit, ensuring Windows Update won’t hog your Internet connection with its background downloads. Windows 10的Fall Cr…

Elasticsearch嵌套查询

2019独角兽企业重金招聘Python工程师标准>>> 一、背景 最近在做基于宴会厅档期的商户搜索推荐时&#xff0c;如果用传统平铺式的mapping结构&#xff0c;无法满足需求场景&#xff0c;于是用到了Elasticsearch支持的Nested(嵌套)查询。 二、普通对象与嵌套对象的索引…

写给深圳首期Python自动化开发周未班的信

你是否做了正确的决定&#xff1f; 深圳首期周未班的同学们大家好&#xff0c;我是Alex, 老男孩教育的联合创始人&#xff0c;Python项目的发起人&#xff0c;51CTO学院连续2届最受学员喜爱的讲师&#xff0c;中国最早一批使用Python的程序员&#xff0c;当然还有一堆头衔&…

网站跳出率的相关要点介绍

今天小峰seo博客和大家一起来探讨关于“网站跳出率的相关要点”&#xff0c;这里大体是分为三大要点&#xff1a;首先是进入的流量渠道&#xff0c;然后就是综合流量速度和内容的质量问题&#xff0c;细的来说就是我们的网站进来的用户是搜索什么关键词来的是通过百度还是搜狗或…

如何使用PowerShell提升开发效率(以Windows Embedded CE为例)

简介 本文讲述如何使用Powershell通过RAPI来控制Windows Embedded CE和Windows Mobile设备。 缘由 我入行的时候是做AS400 RPG和UNIX C开发的&#xff0c;所有开发环境都是字符界面&#xff0c;因此习惯了vigrepmake的开发模式。后来开始做Windows的开发&#xff0c;开始也不大…

视频图像传输学习笔记-基础小知识(一)

摄像头DVP与MIPI区别 DVP是并口&#xff0c;需要PCLK、VSYNC、HSYNC、D[0&#xff1a;11]——可以是8/10/12bit数据&#xff0c;看ISP或baseband是否支持&#xff1b;总线PCLK极限大约在96M左右&#xff0c;而且走线长度不能过长&#xff0c;所有DVP最大速率最好控制在72M以…

java程序员面试交流项目经验

粘贴自&#xff1a;https://blog.csdn.net/wangyuxuan_java/article/details/8778211 1&#xff1a;请你介绍一下你自己 这是面试官常问的问题。一般人回答这个问题过于平常&#xff0c;只说姓名、爱好、工作经验&#xff0c;这些简历上都有。其实&#xff0c;面试官最希望知道…

Windows7旗舰版磁盘分区详解—附分区步骤截图

最近工作中配置使用联想的Thinkpad TL系列本本.当然原装的系统时刚发布的Windows RTM旗舰版.在考虑买之前也参考了戴尔 苹果的等等, 但个人私下也是一直在用Tinkpad系列, 相比其他的品牌本人还是比较钟情于Tinkpad 非常实用的键盘. 以及简洁的外观.买回来一看这个TL系列原装的系…

outlook存档邮件_如何在Outlook 2013中存档电子邮件

outlook存档邮件We’ve always been told that backing up our data is a good idea. Well, that same concept can extend to email as well. You may want to archive your email every so often, such as monthly, quarterly, or even yearly. 我们一直被告知备份数据是一个…

洛谷 P1736 创意吃鱼法(多维DP)

题目描述 回到家中的猫猫把三桶鱼全部转移到了她那长方形大池子中&#xff0c;然后开始思考&#xff1a;到底要以何种方法吃鱼呢&#xff08;猫猫就是这么可爱&#xff0c;吃鱼也要想好吃法 ^_*&#xff09;。她发现&#xff0c;把大池子视为01矩阵&#xff08;0表示对应位置无…

计算机组装和维护_如何构建自己的计算机,第二部分:组装在一起

计算机组装和维护So you’ve selected your parts, double- and triple-checked their compatibility, and waited for economy shipping to bring them all to your door. It’s time to get to the fun part: putting them all together. 因此&#xff0c;您已经选择了零件&a…

Python学习-集合的常见用法

st [1,2,3,4,5] ct [2,3,4,5,76] list set(["name", list, try]) list2 set(["name", list, try, but, test]) # 两个列表去重&#xff0c;利用集合st set(st) #设为集合 ct set(ct) print(st, type(st))sct0 st.union(ct) #并集 sct st | ct …

Autofac之自动装配

从容器中的可用服务中选择一个构造函数来创造对象&#xff0c;这个过程叫做自动装配。这个过程是通过反射实现的 默认 思考这么一个问题,如果注册类型中存在多个构造函数,那么Autofac会选择哪一个来创建类型的实例 答案是"尽可能最多参数" class ConstructorClass {p…