字节型与整型_Java字节码解读

本文详细解析了Java字节码的结构,包括魔数、版本号、常量池、访问标志、类索引、父类索引、接口索引等。通过对class文件的解读,介绍了字段表、方法表和属性表,特别是Code属性,它是方法体的代码存储位置。文章总结了字节码的本质是Java虚拟机的指令,理解这些指令有助于深入理解Java虚拟机的工作原理。
摘要由CSDN通过智能技术生成

1. 字节码

Java字节码是Java虚拟机执行的一种指令格式.class文件是编译器编译之后供虚拟机解释执行的二进制字节码文件.

下面举个例子,写一段Java打码,并编译.

package com.xfhy.test;

public class Hello {
    private int num = 1;

    public int add() {
        num = num + 2;
        return num;
    }
}

编译得到class文件之后,用Hex Fiend软件打开该class文件.

CAFEBABE 00000034 00130A00 04000F09 00030010 07001107 00120100 036E756D
01000149 0100063C 696E6974 3E010003 28295601 0004436F 64650100 0F4C696E
654E756D 62657254 61626C65 01000361 64640100 03282949 01000A53 6F757263
6546696C 6501000A 48656C6C 6F2E6A61 76610C00 0700080C 00050006 01001363
6F6D2F78 6668792F 74657374 2F48656C 6C6F0100 106A6176 612F6C61 6E672F4F
626A6563 74002100 03000400 00000100 02000500 06000000 02000100 07000800
01000900 00002600 02000100 00000A2A B700012A 04B50002 B1000000 01000A00
00000A00 02000000 03000400 04000100 0B000C00 01000900 00002B00 03000100
00000F2A 2AB40002 0560B500 022AB400 02AC0000 0001000A 0000000A 00020000
0007000A 00080001 000D0000 0002000E

class文件内部就是长这个样子. 里面是一堆16进制字节,完全看不懂.JVM是如何解读的?

2. 字节码结构

class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构只有两种数据类型: 无符号数和表.

  • 无符号数: 无符号数可以用来描述数字、索引引用、数量值或按照utf-8编码构成的字符串值.其中无符号数属于基本的数据类型。以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节.
  • 表: 表是由多个无符号数或其他表构成的复合数据结构.所有的表都以“_info”结尾, 由于表没有固定长度,所以通常会在其前面加上个数说明.

class的内容其实就是下面这张表里面的数据顺序排列的,只需要安装这个顺序逐一进行解读就可以了:

类型 名称 说明 长度
u4 magic 魔数,识别 Class 文件格式 4 个字节
u2 minor_version 副版本号 2 个字节
u2 major_version 主版本号 2 个字节
u2 constant_pool_count 常量池计算器 2 个字节
cp_info constant_pool 常量池 n 个字节
u2 access_flags 访问标志 2 个字节
u2 this_class 类索引 2 个字节
u2 super_class 父类索引 2 个字节
u2 interfaces_count 接口计数器 2 个字节
u2 interfaces 接口索引集合 2 个字节
u2 fields_count 字段个数 2 个字节
field_info fields 字段集合 n 个字节
u2 methods_count 方法计数器 2 个字节
method_info methods 方法集合 n 个字节
u2 attributes_count 附加属性计数器 2 个字节
attribute_info attributes 附加属性集合 n 个字节

2.1 魔数

用于标记当前文件是class(为啥不是用后缀来标记该文件为class文件,因为防止后缀被修改,为了安全),固定值为0XCAFEBABE.文件一开始就是这个.

2.2 版本号

魔数后面的00000034是版本号,也是4个字节,其中前2个字节表示副版本号,后2个字节表示主版本号.这里0034对应的值是52,也就是jdk 1.8.0

2.3 常量池

2.3.1 常量池容量计数器

接着是常量池相关的东西了,常量池的数量不固定,需要2个字节来表示常量池容量计数值.demo里面是0013,也就是19.

咱通过javap -verbose Hello命令查看该class的字节码如下(只截取了常量池部分数据):

Constant pool:
   #1 = Methodref          #4.#15         // java/lang/Object."":()V
   #2 = Fieldref           #3.#16         // com/xfhy/test/Hello.num:I
   #3 = Class              #17            // com/xfhy/test/Hello
   #4 = Class              #18            // java/lang/Object
   #5 = Utf8               num
   #6 = Utf8               I
   #7 = Utf8               
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               add
  #12 = Utf8               ()I
  #13 = Utf8               SourceFile
  #14 = Utf8               Hello.java
  #15 = NameAndType        #7:#8          // "":()V
  #16 = NameAndType        #5:#6          // num:I
  #17 = Utf8               com/xfhy/test/Hello
  #18 = Utf8               java/lang/Object

可以看到这里其实序号是从1开始的,而且总共是18个??? 那为啥class文件里面的数值是19?因为它把第0项常量空出来了:这是为了在于满足后面某些指向常量池的索引值的数据在特定情况下需要表达"不引用任何一个常量池项目"的含义,这种情况可用索引值0来表示.

2.3.2 常量解读

首先是第一个常量0x0a,即10.这里的10代表的是CONSTANT_Methodref_info,即类中方法的符号引用. 常量标志数值的含义表:

类型 标志 描述
CONSTANT_utf8_info 1 UTF-8 编码的字符串
CONSTANT_Integer_info 3 整形字面量
CONSTANT_Float_info 4 浮点型字面量
CONSTANT_Long_info 5 长整型字面量
CONSTANT_Double_info 6 双精度浮点型字面量
CONSTANT_Class_info 7 类或接口的符号引用
CONSTANT_String_info 8 字符串类型字面量
CONSTANT_Fieldref_info 9 字段的符号引用
CONSTANT_Methodref_info 10 类中方法的符号引用
CONSTANT_InterfaceMethodref_info 11 接口中方法的符号引用
CONSTANT_NameAndType_info 12 字段或方法的符号引用
CONSTANT_MethodHandle_info 15 表示方法句柄
CONSTANT_MothodType_info 16 标志方法类型
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点

什么是符号引用? 常量池主要存放两大常量,字面量符号引用.

  • 字面量: 文本字符串,声明为final的常量值
  • 符号引用: 类和接口的全限定名,字段的名称和描述符,方法的名称和描述符

知道了该标志的含义,说明接下来的数据就是类中方法的符号引用的数据.但是我们不知道这个数据到底有多长.得看下面这个表格,常量池中的17种数据类型的结构总表,才知道它的结构到底如何:

53ad8a90b8d8e47e14f4aa800f497449.png

f69bae07333ab93d8c91a950f98bc11a.png

9a82975eabe7e270af15e2090cc0e7e7.png

从表中查出CONSTANT_Methodref_info的tag是10,上面已经拿到了.然后接下来的2个u2表示它的数据,在demo中的值为: 0004 000F

  • 前两位的值为0x0004,即 4,指向常量池第 4 项的索引
  • 后两位的值为0x000f,即 15,指向常量池第 15 项的索引

至此,第一个常量就解读完毕了.后面还有17个常量,就不一一解读了,就是查字典.所有的常量都在这里了,它们最后的解读出来是和javap -verbose Hello解读出来的Constant pool是一致的.

0A00 04000F09 00030010 07001107 00120100 036E756D
01000149 0100063C 696E6974 3E010003 28295601 0004436F 64650100 0F4C696E
654E756D 62657254 61626C65 01000361 64640100 03282949 01000A53 6F757263
6546696C 6501000A 48656C6C 6F2E6A61 76610C00 0700080C 00050006 01001363
6F6D2F78 6668792F 74657374 2F48656C 6C6F0100 106A6176 612F6C61 6E672F4F
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值