java实体字节属性定义_Java字节码方法表与属性表详解

ad44733c37c7bdae4113d2bcc8a29730.png

cd3e77fef63920ba60e2dc49ec7c206f.png

而这些字节其实对应的信息是它:

9031e60dab036d2b8a699e37f912e9e2.png

所以问题就来了,aload_0不是助记符信息么,怎么就能够跟字节码文件中的字节对应上呢?所谓助记符其实也就是帮忙我们去记忆的符合,在底层其实也是对应的一个个十六进制的数字的,其它aload_0对应的就是2A这个十六进制数字,凭什么这么说?因为有jclasslib这么好的工具能帮我们对应上,将鼠标放在助记符上发现是一个可以点的链接,如下:

11b9c8666c0c9d0b5d653a0b0ac963ca.gif

点一下“aload_0”发现居然链到了oracle的官网上的说明上去了,如下:

f5d018243114f8ddd9194e18a610505c.png

a3a81fd61470b76e18a33238e97821f6.png

a68ed4fb9487c6938471acfd19b4717b.png

所以第一个字节已经分析完了,确实是跟助记符对应上了,接着来分析第二个字节:

64d8050a54a04e8a346e8c6798af1fa6.png

而在jsclasslib中对应的第二个助记符是“invokespecial”,点击链到官网看一下:

0ee5bfb78dce67c67ceca08a89b76e57.png

而它的作用可以理解成就是调用父类的方法,很明显对于咱们自定义的子类肯定会去调用父类的构造方法,而这个助记符是有参数的:

4a54893c23bbec5d3b9f08ea932924d8.png

其实也就是往后的两个字节就是该助记符所对应的参数,如下:

f2feecf0b3ea0da3dee0d7fd4f747c1a.png

对应常量池为:

888bb45cb5466d64be0e59f24417c77d.png

也就是构造方法嘛,如jsclasslib所示:

1151a674ed8d5ce7702b1a53f37342df.png

接下来继续往下走一个字节:

30b5ce9193480db4867eeb4d23a7276f.png

又对应aload_0,如下:

63a4323059f4c68ed22fc8ef6291c7df.png

接着再往后看一个字节:

3e39116d1c009ade07b142661678d4f0.png

其实它就是对应下一个助记符,如下:

db1157dabc50ef66a2ec3a5c55b48ba0.png

为啥如此任性呢,因为点击查看一下说明就晓了啦:

228592e6c9c70984a974ed9af1b2e4af.png

为啥要push一个1呢?实际就是给咱们定义的成员变量a赋值,如下:

b3bdd84501a80ef23274bcf973fa083b.png

可见,该变量的赋值是在默认构造函数中进行的,而不是直接进行赋值的,这也就是分析字节码文件的好处,可以更加真实的发现底层细节。

接下来再数一个字节:

91e6a686d64bbe4590ca009c2d628e33.png

当然它又对应另一个助记符喽,如下:

ae642a40122ed77dcb0ed1b84f089296.png

点击看一下官网说明:

a64c09599da05c33f26f59fc23b49dab.png

接下来该助记符是携带有参数的,所以再往后数两个字节:

d724004e7787012dc415394903da04f1.png

对应常量池:

e46a63810c8b954e827ab0d9e9a66d73.png

也就是给MyTest1的成员变量a赋值为1。

接下来再数一个字节:

e210718d86618e0631bf128803708dc8.png

对应于如下助记符:

264ba0a7aff88ff235581fc295011e8a.png

点击确认一下:

6ffa6da5d644dcc460c75f7606f055fb.png

至此整个构造方法就已经执行完了。发现通过分析字节码也能获得不少新知识嘛,仅通过这个构造函数的执行流程就能知道了对于我们定义的成员变量原来是在构造方法中进行赋值而非直接赋值的,还是挺有价值的。

好,方法的code分析完之后,则就得往下进行分析了,先来查看一下结构类型:

3da7b9fa3630d9bfc3596c54e4d26a71.png

也就是再数两个字节,看一下:

596c37a557943d1c49ec28b4b33c6566.png

说明该方法木有异常信息,所以接下来的异常表就不会显示在字节文件当中了:

ccd8c2ea858e10c97bd3dd174a2fc46e.png

其中关于异常还需解释一下:

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时,表示处理所有的异常。

接下来就到属性相关的东东了,如下:

085aeb579f1363695fe79846526b749b.png

所以往下数2个字节:

0e8876357136deb9bdd7b95921cf2200.png

说明该方法有两个属性,往下数两个字节则是第一个属性的名字索引,如下:

4673590f0fd821fa780251d462c093f8.png

也就是对应第10的常量池,为:

03c74e7ca02c254789f86f5d9d50284d.png

该属性用来表示code数组中的字节码和Java代码行数之间的关系。这个属性可以用来在调试的时候定位代码执行的行数。而该属性的结构为:

152c6f66ba2403b7ec26435db89c52aa.png

其中attribute_name_index就是常量索引10,接下来数4个字节则是属性的长度attribute_length,如下:

8956615770bb4db94685ff0daa5ccee9.png

也就是属性的长度为10,也就是接下来10个字节则为LineNumberTable的属性信息,如下:

6510d1446f11466747653a594241e886.png

看一下jclasslib:

4cc43b2f95970ee7c504ec8b6fc904d2.png

下面具体来分析一下这10个字节,根据结构体来看:

e7de21421deeab113194dd857d31237e.png

先2个字节表示属性表有几对映射,如下:

965b7ecdd3092e6c258f663ab898bea7.png

说明有两对映射,然后再回到结构体中,每对映射的内容为:

56306f6e48b5e210aa12c34b45a3e9a5.png

每对占4个字节,先看第一对映射:

39a9a74eb74c2d09cb55b282b713273c.png

也就是start_pc=0;line_number=3,对应于jclasslib:

ce609208302fcef048ec74841ee815a5.png

由于咱们源代码木有构造方法,所以字节码对应源代码就在第3行,如下:

aa2521f357b011570d57477f94fa5092.png

接下来看第二对映射:

620a9baabccd73a9be49e9df13b2f408.png

也就是start_pc=4;line_number=4,对应于jclasslib:

c9b04086914f26eac1e8da45ba532981.png

因为成员变量的赋值是在构造方法中完成的,所以对应第4行代码:

d62a29108260b2db174ad92cca95c0a9.png

好,方法的第一个属性已经完了,接下来以同样的顺序来查看方法的第二个属性信息了,走2个字节来看属性名称索引,如下:

919f4aad6897a43b85496c38bed45b3a.png

对应第11个常量池索引,如下:

843cfe7c0696a804ceab3ce6d4d4ecf3.png

它的结构跟LineNumberTable差不多的,往后数四个字节则是局部变量表所占的长度:

8b5212a53f2cf596af58eb6ccdb8c9be.png

329a514af43313077f69743f05bc3036.png

长度为12,如jclasslib所示:

c11b480b75275b8354aa716d3f6c04b5.png

然后往后数12个字节则是局部变量的具体信息,首先两个字节则为局部变量的个数,如下:

07bafe89244669157384e3b8a3499536.png

呃~~构造方法哪来的局部变量呢,好奇怪,先不管先来把其它字节分析完,再往后四个字节表示start_pc和length,如下:

e328d139ff15d1d6459741feae4edd94.png

如jclasslib所示:

c35f2c58f1fb8582e9dc5e146d289163.png

接下来则为局部变量的索引为0,也就是第一个局部变量:

97505d240b5b29fbb67842d0585246a5.png

再往后两个字节则是局部变量对应常量池的索引,如下:

e901b98c8356b335ef270cea2dbef79a.png

8700026b76a01f11b028ff431121363d.png

再接下来两个字节则是对该局部变量的一个描述常量索引,如下:

c09966a6db9b0178db4cdb7e11500814.png

9c85eb0662dbe442a2c9db2165a19c0d.png

所以对应jclasslib中可以看到:

74df4f0f5fd2cb4b34a5ef8f2b5d1e4e.png

那思考一下为啥在构造方法中会有一个this的局部变量呢?我们知道在所有方法中我们都能使用this关键字来访问当前的对象,而从字节层面来讲其实this是作为方法的第一个参数传进来的,也就是说对于Java的一个实例方法而言最少会有一个this的局部变量存在!

还剩最后两个字节则为stackmaptable信息,JDK1.6加入的,主要做校验检查的,因为0嘛所以后面肯定木有相关的信息了,这里就直接忽略,如下:

6b1d99881d0e234f02598ea8d105c4c5.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值