.class文件结构分析

1、class文件的结构
字节码文件的结构包括:魔数、版本号、常量池、访问标志、类索引以及父类索引或者接口索引信息(集合)、字段(类变量和成员变量)信息(集合)、方法信息(集合)
java class文件的整体结构如下:

名称释义大小
magic魔数4 Byte
minor_version子版本号2Byte
major_version主板本号2Byte
constant_pool_count常量池的长度2Byte
constant_pool常量池的内容有constant_pool_count决定
access_flags访问标志位2Byte
this_class类索引2Byte
super_class父类索引2Byte
interfaces_count实现接口的数目2Byte
interfaces实现的接口由interfaces_count决定
fields_count成员变量的数目2Byte
fields成员变量由fields_count决定
methods_count方法数2Byte
methods方法由methods_count决定
attributes_count属性数2Bytes
attributes属性由attributes_count决定

对于一端java代码:

public class MyClassTest {
	private int a = 1;

	public int getA() {
		return a;
	}
	public void setA(int a) {
		this.a = a;
	}
}

使用 javap -verbose MyClassTest.class解析出二进制字节码

F:\workspace\JvmTest\bin\xcs\com\cn>javap -verbose MyClassTest.class
Classfile /F:/workspace/JvmTest/bin/xcs/com/cn/MyClassTest.class
  Last modified 2019-8-29; size 483 bytes
  MD5 checksum e6455c493674f12e813ea5c766e419fe
  Compiled from "MyClassTest.java"
public class xcs.com.cn.MyClassTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // xcs/com/cn/MyClassTest
   #2 = Utf8               xcs/com/cn/MyClassTest
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Methodref          #3.#11         // java/lang/Object."<init>":()V
  #11 = NameAndType        #7:#8          // "<init>":()V
  #12 = Fieldref           #1.#13         // xcs/com/cn/MyClassTest.a:I
  #13 = NameAndType        #5:#6          // a:I
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lxcs/com/cn/MyClassTest;
  #18 = Utf8               getA
  #19 = Utf8               ()I
  #20 = Utf8               setA
  #21 = Utf8               (I)V
  #22 = Utf8               SourceFile
  #23 = Utf8               MyClassTest.java
{
  public xcs.com.cn.MyClassTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>
":()V
         4: aload_0
         5: iconst_1
         6: putfield      #12                 // Field a:I
         9: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 3: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lxcs/com/cn/MyClassTest;

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

  public void setA(int);
    descriptor: (I)V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #12                 // Field a:I
         5: return
      LineNumberTable:
        line 10: 0
        line 11: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lxcs/com/cn/MyClassTest;
            0       6     1     a   I
}
SourceFile: "MyClassTest.java"

1)魔数:4个字节,java的标志,值为CAFEBABE
2)版本号:紧跟魔数之后的4个字节,前两个字节是minor version(次版本号),后两个字节是major version(主版本号)。
3)常量池(constant pool):紧接着主版本号之后就是常量池入口,是class文件的资源仓库,java类中的很多信息都是由常量池来维护和描述的,常量池是class文件中最大的数据项目之一。
----常量池开始的两个字节表示常量池的项目数,一般从1开始计数;比如前两个字节 00 16表示长度是22,但是只有21项常量,因为从1开始计数,0索引通常表示"不引用任何一个常量池项",但是对于字段、方法集合索引都是从0开始。

----常量池中主要存放两大类:
------字面量和符合引用。字面量比如文本字符串、声明为final的常量值等。
------而符号引用包括:
类和接口的全限定名
字段的名称和描述符(描述符是指访问控制符、类型等信息)
方法的名称和描述符(指方法的参数个数、类型、顺序、返回值等)。

------常量池的每一项常量都是一张表,标的结构不固定,但是表的第一项内容是u1(一个字节)类型的,通常表示字符串、整形、浮点型等。

常量池的常量项表有14个,如下图:
在这里插入图片描述
常量池每一张表的结构:
在这里插入图片描述
每个表的结构:
第一个tag(u1)表示是什么类型的表,比如3代表整形表;
第二个name_index(u2)表示,如果是基本类型,表示该基本类型变量的值所在的class中的位置的索引。如果是引用类型,比如String,第二个index代表String的长度,
第三个是String的值,使用UTF-8缩略码表示。

注:UTF-8缩略码与普通UTF-8编码的区别
UTF-8缩略码:从‘\u0001’到‘\u007f’之间的字符(相当于1-127的ASCII码)的缩略码使用一个字节表示;从’\u0080’到’\u07ff’之间的所有字符的缩略码使用两个字节表示;从’\u0800’到’\uffff’之间的所有字符的缩略码就是普通UTF-8的规则使用3个字节表示。

4)访问标志:常量池之后的两个字节,表示该类或者接口的访问标志public ,protected,如果是类是否被声明为final。如果一个类被public和final共同修饰,则使用这两个值的并集表示,比如public是0X0001,final是0X0010,则这个类的访问修饰符对应的字节码值是0X0011。
访问修饰符标志表如下:
在这里插入图片描述
5)类索引以及父类索引或者接口索引信息(集合):在访问标志位后面紧接着的2个字节表示当前类的全限定名的索引值,再接着2个字节表示父类的全限定名的索引值;接下来接口由多个2字节表示,第一个2字节表示有多少个接口,比如是3表示有个接口;接下来的3个2字节分别大鸟3个接口的全限定名索引值。
注意:给出的都是索引值,根据索引可以在常量池中找到他们对应的真是字符串的值

6)字段表:在类或接口信息之后,就是字段表(类变量或者成员变量,不包括方法中的局部变量)。
字段表结构如下图:
在这里插入图片描述
其中名字索引对应常量池中的字段名称引用,描述符索引对应字段的类型,是基本类型还是引用类型还是void(对应方法)。

7)方法表:在字段表之后的两个字节表示有多少个方法,之后就是每个方法的结构。一个方法表中包括:访问标志符、方法名索引、描述索引(参数、返回值等)、属性长度、属性表(主要包括最大栈深度、本地变量表、以及Code,code就是方法中的具体代码编译成的字节码指令,在执行方法时被JVM执行的指令)

在这里插入图片描述
8)属性表:属性表示方法表或者字段表里面的一部分,不是单独存在的。比如方法表中的Code、字段final关键字的常量值都属于属性表的内容。以及异常,存在于方法表,也是属性表的范畴。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值