美文网首页
class文件和字节码解析

class文件和字节码解析

作者: 程序员札记 | 来源:发表于2022-05-18 22:07 被阅读0次

通过《编译原理》的相关学习,我们知道我们编写的Java代码最终会被翻译成class文件。Class文件格式是JVM自己定义的用于表示Java类的二进制字节流规范,与操作系统本身无关,该文件格式正是Java代码一次编译,跨平台运行的关键。

class文件

image.png

其中u 表示n个无符号字节,如u4 magic 表示magic的取值用4个无符号字节表示,cp_info描述常量池的结构,field_info描述字段的数据结构,method_info描述方法的数据结构,attribute_info描述属性的数据结构。ClassFile结构各项的含义如下:

  • magic: 魔数,用于标识当前Class文件的文件格式,JVM可据此判断该文件是否可以被解析,目前固定为0xCAFEBABE
  • minor_version, major_version:minor_version是副版本号,major_version是主版本号,这两个版本是生成Class文件时根据编译的JDK版本来确定的,用标识编译时的JDK版本,常见的一个异常Unsupported
  • major.minor version 52.0就是因为运行时的JDK版本低于编译时的JDK版本,52是Java8的主版本号。
  • constant_pool_count:常量池计数器,等于常量池中的成员数加1
  • constant_pool:常量池,是一种表结构,包含class文件结构和子结构中引用的所有字符串常量,类或者接口名,字段名和其他常量,其有效索引范围是1- (constant_pool_count-1)。其中类和接口名采用全限定形式,即在整个JVM中的绝对名称,如java.lang.Object,方法名,字段名、局部变量名和形参名都采用非限定名,即在源代码文件中使用相对名称,如属性名name。
  • access_flags:用于表示某个类或者接口的访问权限和属性
  • this_class:类索引,该值必须是对常量池中某个常量的一个有效索引值,该索引处的成员必须是一个CONSTANT_Class_info类型的结构体,表示这个class文件所定义的类和接口
  • super_class:父类索引,同this_class,该值必须是对常量池中CONSTANT_Class_info类型常量的一个有效索引值,如果该值为0,则只能表示java.lang.Object类,因为该类是唯一一个没有父类的类。
  • interfaces_count:接口计数器,表示当前类或者接口的直接超接口的数量
  • interfaces:接口表,是一个表结构,每个成员同this_class,必须是对常量池中CONSTANT_Class_info类型常量的一个有效索引值,其有效索引范围为0~interfaces_count,接口表中成员的顺序与源代码中给定的接口顺序是一致的,interfaces[0]表示源代码中最左边的接口。
  • fields_count:字段计数器,当前class文件所有字段的数量
  • fields:字段表,是一个表结构,表中每个成员必须是filed_info数据结构,用于表示当前类或者接口的某个字段的完整描述,不包含从父类或者父接口继承的字段
  • methods_count:方法计数器,表示当前类方法表的成员个数
  • methods:方法表,是一个表结构,表中每个成员必须是method_info数据结构,用于表示当前类或者接口的某个方法的完整描述,包含当前类或者接口定义的所有方法,如实例方法、类方法、实例初始化方法等,不包含从父类或者父接口继承的方法
  • attributes_count:属性计数器,表示当前class文件attributes属性表的成员个数
  • attributes:属性表,是一个表结构,表中每个成员必须是attribute_info数据结构,这里的属性是对class文件本身,方法或者字段的补充描述,如SourceFile属性用于表示class文件的源代码文件名。
// 为是一个简单的例子
public class ClassFileTest {
    private int a = 5;
    public int getA(){
        return this.a;
    }
    public static void main(String[] args) {
        new ClassFileTest().getA();
    }
}

字节码

// javap -v
public class ClassFileTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#24         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#25         // ClassFileTest.a:I
   #3 = Class              #26            // ClassFileTest
   #4 = Methodref          #3.#24         // ClassFileTest."<init>":()V
   #5 = Methodref          #3.#27         // ClassFileTest.getA:()I
   #6 = Class              #28            // java/lang/Object
   #7 = Utf8               a
   #8 = Utf8               I
   #9 = Utf8               <init>
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               LClassFileTest;
  #16 = Utf8               getA
  #17 = Utf8               ()I
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Utf8               args
  #21 = Utf8               [Ljava/lang/String;
  #22 = Utf8               SourceFile
  #23 = Utf8               ClassFileTest.java
  #24 = NameAndType        #9:#10         // "<init>":()V
  #25 = NameAndType        #7:#8          // a:I
  #26 = Utf8               ClassFileTest
  #27 = NameAndType        #16:#17        // getA:()I
  #28 = Utf8               java/lang/Object
{
  public ClassFileTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_5
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 1: 0
        line 3: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   LClassFileTest;

  public int getA();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field a:I
         4: ireturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LClassFileTest;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: new           #3                  // class ClassFileTest
         3: dup
         4: invokespecial #4                  // Method "<init>":()V
         7: invokevirtual #5                  // Method getA:()I
        10: pop
        11: return
      LineNumberTable:
        line 10: 0
        line 11: 11
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      12     0  args   [Ljava/lang/String;
}

例如#2对应类型是Fieldref,表示为ClassFileTest.a:I.
例如#5对应类型是Methodref,表示为ClassFileTest.getA:()I.
什么意思?

描述符

描述符有两种,字段描述符和方法描述符,本质就是一个基于特定规则的字符串,其中字段描述符用来表示类,实例和局部变量的类型,具体如下:
ClassFileTest.a:I 表示 ClassFileTest类中int成员变量a.
ClassFileTest.getA:()I.表示 ClassFileTest类中返回值是int的getA方法。


image.png

常量池

Java虚拟机指令不依赖类,接口,类实例或数组的运行时内存布局,而是依赖依赖常量池表中的符号信息,常量池表中所有项都有如下通用格式:

cp_info{
   u1 tag;//类型标记,用于确定后面的info的格式,tag是一个字节
   u1 info[];//两个或者多个字节,取决于tag的值
}

CONSTANT_Utf8_info:用于表示一个Utf8编码的字符串

CONSTANT_Utf8_info{
   u1 tag;//tag取值1
   u2 length;//后面的byte数组的长度
   u1 bytes[length];//字符串对应的byte数组数据
}

CONSTANT_Class_info:用于表示一个Java类或者接口名

CONSTANT_Class_info{
   u1 tag;//tag取值7
   u2 name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
}

CONSTANT_Fieldref_info:用于描述一个字段

CONSTANT_Fieldref_info{
   u1 tag;//tag取值9
   u2 class_index;//常量池中的有效索引,该索引处的成员必须是一个CONSTANT_Class_info结构,表示该字段所属的类
   u2 name_and_type_index;//常量池中的有效索引,该索引处的成员必须是一个CONSTANT_NameAndType_info结构,该结构用于表示一个字段或者方法描述符。
}

CONSTANT_MethodType_info:用于记录方法的类型信息,即方法描述符

CONSTANT_MethodType_info{
   u1 tag;//tag取值21
   u2 name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u2 descriptor_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
}

更多类型请参考《Java虚拟机规范8版》

字段

feild_info{
   u2 access_flags;//字段标识
   u2 name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u2 descriptor_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u2 attributes_count;//当前字段附加属性数值
   attribute_info attributes[attributes_count];//属性表中的每个成员
}

方法

method_info{
   u2 access_flags;//方法标识
   u2 name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u2 descriptor_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u2 attributes_count;//当前字段附加属性数值
   attribute_info attributes[attributes_count];//属性表中的每个成员
}

属性

ClassFile、filed_info、method_info结构和Code属性都有属性表,所有的属性都通过attribute_info结构表示,其通用格式如下:

attribute_info{
   u2 attribute_name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u4 attribute_length;//表示后面的info信息的字节长度
   u1 info[attribute_length];//具体数据
}

Java8预定义了23种属性(《Java虚拟机规范8版》中有介绍),例

Code:位于method_info的属性表中,表示该方法的虚拟机指令及辅助信息,method_info中有且仅有一个Code属性,其结构如下:

attribute_info{
   u2 attribute_name_index;//对常量池的有效索引,该索引处的成员必须是一个CONSTANT_Utf8_info结构
   u4 attribute_length;//表示后面的info信息的字节长度
   u2 max_stack;//当前方法操作数栈的最大深度
   u2 max_locals;//此方法引用局部变量表中的局部变量的个数,包含传递方法入参的局部变量
   u4 code_length;//后面的code数组的字节长度
   u1 code[code_length];//当前方法的虚拟机指令的数据
   u2 exception_table_length;//后面的exception_table数组的长度;
   {
      u2 start_pc;
      u2 end_pc;//try/catch的代码范围,具体来说是起止代码对应的虚拟机指令在code数组中的索引
      u2 handler_pc;//异常处理逻辑的代码的虚拟机指令在code数组中的索引
      u2 catch_type;//常量池中一个类型为CONSTANT_Class_info的有效索引,表示捕获的异常类型。
   }exception_table[exception_table_length];//此方法的捕获的各异常的异常处理逻辑
}

用户在编译源代码文件时可以添加新的属性,只要JVM实现能够正确识别该属性即可,注意用户自定义的属性不能使用已有预定义属性的属性名

虚拟机指令集

C/C++的方法会被编译成特定于CPU架构的汇编指令,然后交由CPU逐一执行,因为汇编指令与CPU架构是强绑定的,所以C/C++程序在执行前需要在不同CPU架构的机器上编译一遍。Java为了实现一处编译,跨平台运行的目标,在汇编指令之上引入了一个独立于平台的中间层,虚拟机指令,由Java虚拟机规范提供指令标准定义,由Java虚拟机厂商提供指令实现,不同平台的Java虚拟机都遵循相同的指令集规范,从而实现跨平台运行目标。一个方法对应的一组虚拟机指令称为这个方法的字节码(byte codes)。

具体虚拟机指令集请查询《Java虚拟机规范8版》,例:

  public int getA();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #2                  // Field a:I
         4: ireturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LClassFileTest;

操作码 助记符 指令含义 例子操作
42 aload_0 将第一个引用类型本地变量推送至栈顶 this对象放入栈顶
180 getfield 获取指定类的实例字段,并将值压入栈顶 获取a的值
172 ireturn 从当前方法返回int 返回a的值
主要参考
《hotspot实战》
《Java虚拟机规范8版》
Hotspot class文件和字节码解析

解析流程

以下面这个例子来说明解析过程


image.png

字节码文件解析流程图,从上到小解析就好了
其实解析字节码就想摩斯密码一样,有一个对应的密码本。对照着就可以解析了。具体可以看书《JVM虚拟机规范》

u1的意思是: 占1个字节 (16进制的一个字节占两位00)
u2的意思是: 占2个字节
u4的意思是: 占4个字节
!的意思是:不确定,是动态计算的

image.png

开始解析

首先说下:上面的字节码都是16进制的,需要计算成10进制的,其次可以看到分成三部分,左边address部分和右边dump部分是没有用的,我们直接解析中间的。还有并不是一排表示一个东西。最后我会把我解析的这个类的信息贴出来。

魔数

ca fe ba be:魔术,表示是一个合格的class文件

为什么会有魔数?魔数有什么用?
其实就是JVM判断是不是一个合格的class文件,如果是就继续往下面读

次版本号和主版本号是指java版本的版本号,看图
00 00:次版本号。这个没啥好解释的把
00 34:主版本号 (3*15+4=52)= jdk1.8


image.png

解析常量池

constant_pool_count是常量池大小
00 20 =32。这里需要注意常量池是从1开始的,所以要减一,理论上是32个,实际是31个。具百度说,0是null。看图验证:工具是jclasslib,idea的插件


image.png

常量池解析

常量池选项属性图。 下面有些属性我有解释,但是具体的解释最好还是看虚拟机规范


image.png
第一个常量池
    Methodref_info {
        u1 tag; 0A=10
        u2 class_index;  00 05  指向常量池5
        u2 name_and_type_index; 00 1A   它表示当前字段或方法的名字和描述符
    }

第二个常量池,后面一样的我就不解释了

    Fieldref_info {
    u1 tag; 09
    u2 class_index; 00 04
    u2 name_and_type_index; 00 1B   
}   

第三个常量池

    Fieldref_info {
    u1 tag; 09
    u2 class_index; 00 04
    u2 name_and_type_index; 00 1C 
  } 
image.png

…后面的我就省略了,一样的

https://img-blog.csdnimg.cn/20200808181320419.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjgxMjk4Ng==,size_16,color_FFFFFF,t_70

access_flags 类修饰符

00 21 = public 和 super

this_class 当前类

00 04 指向常量池,当前类

image.png

super_class

00 05 指向常量池,父类

interfaces_count :实现的接口数量

00 00 :0那么就跳过interfaces[]

fields_count

00 02 表示该类或接口声明的类字段或者实例字段个数,说白了就是你的成员变量有几个

    fields_info[
        field_info {
                u2 access_flags; 00 08  access_flags 项的值是用于定义字段被访问权限和基础属性的掩码标志 请对表
                u2 name_index; 00 06    指向常量池
                u2 descriptor_index; 00 07  描述符
                u2 attributes_count; 00 00
                attribute_info attributes[attributes_count];  就是如果上面哪个count不为0,这里又是一个数组
            }
        field_info {
                u2 access_flags; 00  08 
                u2 name_index; 00 08
                u2 descriptor_index; 00 07
                u2 attributes_count; 00 00
                attribute_info attributes[attributes_count];
            }

methods_count

00 03 =3个方法个数 应该会好奇为啥会是三个哈?我这明明只写了一个。因为我本身main有一个,构造函数有一个,clint也是一个。clint这个方法是动态生成的,如果类中有静态属性或者静态块就会生成这个方法

解析方法,最难的

methods_info[
    method_info {
        u2 access_flags; 00 01 access_flags 项的值是用于定义当前方法的访问权限和基本属性的掩码标志
        u2 name_index; 00 09 指向常量池
        u2 descriptor_index; 00 0A 方法描述符 V代表返回值是void 其他跟字段描述符一样
        u2 attributes_count; 00 01 code属性个数
        attribute_info attributes[attributes_count];
        attributes[
            Code_attribute {
                    u2 attribute_name_index; 00 0B  指向常量池,表示字符串code
                    u4 attribute_length; 00 00 00 2F attribute_length这个意思是下面所有的字节数加起来是这个数;attribute_length 项的值表示当前属性的长度,不包括开始的 6 个字节
                    u2 max_stack; 00 01  操作栈数量,是栈帧里面的 在任意时刻,操作数栈都会有一个确定的栈深度,一个 long 或者 double 类型的数据会占用两个单位的栈深度,其他数据类型则会占用一个单位深度
                    u2 max_locals; 00 01 max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数
                    u4 code_length; 00 00 00 05  code_length 项给出了当前方法的 code[]数组的字节数
                    u1 code[code_length]; 2A  B7 00 01 B1 code[]数组给出了实现当前方法的 Java 虚拟机字节码---方法体或者说是字节码指令
                    u2 exception_table_length; 00 00  异常
                    {  u2 start_pc;
                    u2 end_pc;
                    u2 handler_pc;
                    u2 catch_type;
                    } exception_table[exception_table_length];
                    u2 attributes_count; 00 02 表示attributes数组的个数
                    attribute_info attributes[attributes_count];
                    attributes[
                        LineNumberTable_attribute {  为什么我知道是这个属性勒?因为00 0C指向常量池12,而12就是LineNumberTable_attribute。
                                u2 attribute_name_index;  00 0C
                                u4 attribute_length; 00 00 00 06  attribute_length 给出了当前属性的长度,不包括开始的 6 个字节
                                u2 line_number_table_length; 00 01  说明line_number_table数组的个数,而line_number_table里的元素就是下面的这个{}
                                line_number_table[line_number_table_length];
                                [
                                    {  
                                        u2 start_pc;  00 00  code数组的索引
                                       u2 line_number;  00 08  line_number 项的值必须与源文件的行数相匹配
                                    }
                                ]
                            }
                        LocalVariableTable_attribute {
                                u2 attribute_name_index; 00 0D     指向常量池
                                u4 attribute_length; 00 00 00 0c   当前属性的长度,不包括开始的 6 个字节
                                u2 local_variable_table_length; 00 01   local_variable_table[]数组的成员个数
                                local_variable_table[local_variable_table_length];
                                [
                                    {  
                                        u2 start_pc; 00 00  start_pc是local_variable_table的下标
                                        u2 length;  00 05   length两种意思。具体的看书
                                        u2 name_index; 00 0E 指向常量池,表示一个局部变量的有效的非全限定名
                                        u2 descriptor_index; 00 0F 字段描述符
                                        u2 index;  00 00    index为此局部变量在当前栈帧的局部变量表中的索引
                                    }
                                ] 
                            }
                    
                    ]
                }
        ]   
    }


method_info {
        u2 access_flags; 00 09 public static 修饰符 可以相加的
        u2 name_index;  00 10
        u2 descriptor_index; 00 11
        u2 attributes_count; 00 03
        attribute_info attributes[attributes_count];
        attributes[
            Code_attribute {
                    u2 attribute_name_index; 00 0B  指向常量池,表示字符串code
                    u4 attribute_length; 00 00 00 2B attribute_length这个意思是下面所有的字节数加起来是这个数;attribute_length 项的值表示当前属性的长度,不包括开始的 6 个字节
                    u2 max_stack;  00 00  操作栈数量,是栈帧里面的 在任意时刻,操作数栈都会有一个确定的栈深度,一个 long 或者 double 类型的数据会占用两个单位的栈深度,其他数据类型则会占用一个单位深度
                    u2 max_locals;  00 01 max_locals 项的值给出了分配在当前方法引用的局部变量表中的局部变量个数
                    u4 code_length; 00 00 00 01  code_length 项给出了当前方法的 下面的code[]数组的字节数
                    u1 code[code_length]; B1 code[]数组给出了实现当前方法的 Java 虚拟机字节码---方法体或者说是字节码指令
                    u2 exception_table_length; 00 00  异常
                    {  u2 start_pc;
                    u2 end_pc;
                    u2 handler_pc;
                    u2 catch_type;
                    } exception_table[exception_table_length];
                    u2 attributes_count; 00 02 表示attributes数组的个数
                    attribute_info attributes[attributes_count];
                    attributes[
                        LineNumberTable_attribute {  为什么我知道是这个属性勒?因为00 0C指向常量池12,而12就是LineNumberTable_attribute。
                                u2 attribute_name_index;  00 0C
                                u4 attribute_length; 00 00 00 06  attribute_length 给出了当前属性的长度,不包括开始的 6 个字节
                                u2 line_number_table_length; 00 01  说明line_number_table数组的个数,而line_number_table里的元素就是下面的这个{}
                                line_number_table[line_number_table_length];
                                [
                                    {  
                                        u2 start_pc;  00 00  code数组的索引
                                       u2 line_number;  00 10  line_number 项的值必须与源文件的行数相匹配
                                    }
                                ]
                            }
                        LocalVariableTable_attribute {
                                u2 attribute_name_index; 00 0D     指向常量池
                                u4 attribute_length; 00 00 00 0c   当前属性的长度,不包括开始的 6 个字节
                                u2 local_variable_table_length; 00 01   local_variable_table[]数组的成员个数
                                local_variable_table[local_variable_table_length];
                                [
                                    {  
                                        u2 start_pc; 00 00  start_pc是local_variable_table的下标
                                        u2 length;  00 01   length两种意思。具体的看书
                                        u2 name_index; 00 12 指向常量池,表示一个局部变量的有效的非全限定名
                                        u2 descriptor_index; 00 13 字段描述符
                                        u2 index;  00 00    index为此局部变量在当前栈帧的局部变量表中的索引
                                    }
                                ] 
                            }
                    
                    ]
                },
                Exceptions_attribute {
                    u2 attribute_name_index; 00  14 指向常量池20,代表字符串exceptions
                    u4 attribute_length; 00 00 00 04 attribute_length 项的值给出了当前属性的长度,不包括开始的 6 个字节
                    u2 number_of_exceptions; 00 01  exception_index_table数组成员个数
                    u2 exception_index_table[number_of_exceptions]; 
                        [
                            Class_info {
                                u1 tag; 默认等于00 07 
                                u2 name_index; 00 15 指向常量池
                            }
                        ]
                },
                { 这个属性我没找到 methodParamters
                00 16 00 00 00 05 01  00 12 00 00属于methodparameters
                }
                
        ]
    }

method_info { 第三个不解析了太累了
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }

方法解析完

image.png

attributes_count

00 01 类属性

attributes[attributes_count] = attributes[1]
    [
        SourceFile_attribute  {
            u2 attribute_name_index;  00 18
            u4 attribute_length; 00 00 00 02
            u1 sourcefile_index; 00 19
            }
    ]

一些需要用到对应表,最好看书,详细
字段描述符图


image.png

类和属性访问修饰符图,这个数可以相加,比如0x0009就是public static

image.png

下面是一些解析的时候一些属性集合

field_info

field_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

method_info

method_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
    }

attribute_info

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
    }

Code_attribute

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
        {  u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
        } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
    }

LineNumberTable_attribute

LineNumberTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 line_number_table_length;
    {  u2 start_pc;
    u2 line_number;
    } line_number_table[line_number_table_length];
    }

LocalVariableTable

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}

SourceFile_attribute

SourceFile_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 sourcefile_index;
    }

Java虚拟机规范pdf带目录地址

Java虚拟机规范pdf带目录

相关文章

  • Effect JAVA -机制与原理

    JAVA字节码.Class解析 不论该字节码文件来自何方,由哪种编译器编译,甚至是手写字节码文件,只要符合java...

  • 新鲜出炉,深入讲解java反射的底层原理,这篇算讲的不错了!

    反射 反射 Java代码和Java文件 Java文件和.class字节码文件 class字节码文件在内存中的位置 ...

  • 27-javap指令

    一、解析字节码的意义 javap是JDK自带的反解析工具。它的作用就是根据 Class 字节码文件,反解析出当前类...

  • class(一) 字节码文件结构

    class文件与虚拟机 .class文件内容 常量池解析(重点掌握) 1.Class字节码文件由来 Java能够实...

  • class文件和字节码解析

    通过《编译原理》的相关学习,我们知道我们编写的Java代码最终会被翻译成class文件。Class文件格式是JVM...

  • class文件和字节码解析

    讲解了Java类和对象在内存中的表示机制,Java对象是根据Java类创建的,表示一个Java类实例;Java类是...

  • class文件字节码解析

    本篇文章将介绍 .class 文件的结构,通过一个简单的例子认识 .class 文件。首先写一个java文件(本人...

  • class字节码文件解析

    文件结构 Java class文件是8位字节的二进制流,数据项按顺序存储在class文件中,相邻的项之间没有任何间...

  • Java字节码结构解析

    本文通过解析Class文件中字节码的结构,来加深对Java类文件结构的理解。建议先阅读Java类文件结构解析这篇文...

  • 03 java字节码文件

    java源码经过编译,生成class字节码文件,JVM加载class文件执行。字节码文件将java语言与JVM解耦...

网友评论

      本文标题:class文件和字节码解析

      本文链接:https://www.haomeiwen.com/subject/cifzurtx.html