类文件结构之一:魔数、版本号和常量池

时间:2021-03-26 17:19:57

1、有类如下:

package jvm.loadingclass;

public class TestClass {
    private int m;
    public int inc() {
        return m + 1;
    }
}

2、编译之后:

类文件结构之一:魔数、版本号和常量池

  • 0、1、2、3字节为魔数CAFEBABE;
  • 4,5为次版本号,6,7为主版本号,0x34=52表示jdk1.8;
  • 8、9字节0x16=22,表示有21个常量,索引范围为1-21,其中索引0较为特殊,用来达到“不指向常量池的任意一个常量”;
  • A字节0x07,查“常量池的项目类型表”为CONSTANT_Class_info,其结构为下表,故而B、C字节为0x0002,指向第二个常量,内容为jvm/loadingclass/TestClass;
类型 名称 数量
u1 tag 1
u2 name_index 1
  • 0x0D字节为0x01001A6A…,查表知0x01对应CONSTANT_Class_info类型,查表得其结构如下表,由下表知: 其中0x01表示tag,0x001A为长度,是26,接着是26字节的用UTF-8缩略编码表示的字符串,为jvm/loadingclass/TestClass;
类型 名称 数量
u1 tag 1
u2 length 1
u1 bytes length

- UTF-8缩略编码:从‘\u0001’到‘\u007f’(相当于ASCII的1-127)用1个字节表示,从’\u0080’到‘\u07ff’用2个字节表示,从’\u0800’到’\uffff’用3个字节表示,具体的可以参照链接:UTF-8 可变编码格式,因为26个字母都在‘\u0001’到‘\u007f’之间,用一个字符表示,故而上图的“001A”对应26个字符jvm/loadingclass/TestClass,下图我加上一个中文“中”字,一个“中”需要3个字符表示,长度也随之变为“001D”,E4B8AD表示”中”字
类文件结构之一:魔数、版本号和常量池

  • 0x5E字节: 0x0A0003000B Methodref_info(u1u2u2),指向3和11,得: java/lang/Object. < init>:()V
  • 0x63字节:0x0C00070008 NameAndType(u1u2u2) 指向7.8:< init>得:()V
  • 0xC1字节: 0x0900010013 Fieldref_info(u1u2u2),指向1和19得: jvm/loadingclass/TestClass.m:I

3、获得所有常量:

序号   位置     常量
1     0x0A     0x070002    类引用,指向第22     0x0D     0x01001A6A… jvm/loadingclass/TestClass
3     0x2A     0x070004     类引用,指向第四个
4     0x2D     0x0100106A… java/lang/Object
5     0x40     0x0100016D   m
6     0x44     0x01000149    I
7     0x48     0x010006…     <init>
8     0x51     0x010003…    ()V
9     0x57     0x010004     Code
10    0x5E     0x0A0003000B Methodref_info(u1u2u2),指向311:
                                             java/lang/Object. <init>:()V
11    0x63     0x0C00070008 NameAndType(u1u2u2) 指向7.8:<init>:()V
12    0x68     0x01000FLineNumberTable
13    0x7A     0x010012LocalVariableTable
14    0x8f     0x010004…   this
15    0x96     0x01001CLjvm/loadingclass/TestClass;
16    0xB5     0x010003…  inc
17    0xBB     0x010003…   ()I
18    0xC1     0x0900010013 Fieldref_info(u1u2u2),指向119:
                            jvm/loadingclass/TestClass.m:I
19   0xC6      0x0C00050006 NameAndType:m:I
20   0xCB      0x01000ASourceFile
21   0xD8     0x01000ETestClass.java

4、附录:
完整的编译后的文件(WinHex打开):
类文件结构之一:魔数、版本号和常量池
使用javap查看TestClass.class文件:

Classfile /F:/LAMP/MYWorkspaces/LearningJAVA/bin/jvm/loadingclass/TestClass.class
  Last modified 2017-10-19; size 387 bytes
  MD5 checksum df061cfaf6582f57693ebeb55c890962
  Compiled from "TestClass.java"
public class jvm.loadingclass.TestClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // jvm/loadingclass/TestClass
   #2 = Utf8               jvm/loadingclass/TestClass
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               m
   #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 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               Ljvm/loadingclass/TestClass;
  #16 = Utf8               inc
  #17 = Utf8               ()I
  #18 = Fieldref           #1.#19         // jvm/loadingclass/TestClass.m:I
  #19 = NameAndType        #5:#6          // m:I
  #20 = Utf8               SourceFile
  #21 = Utf8               TestClass.java
{
  public jvm.loadingclass.TestClass();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Ljvm/loadingclass/TestClass;

  public int inc();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #18                 // Field m:I
         4: iconst_1
         5: iadd
         6: ireturn
      LineNumberTable:
        line 6: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       7     0  this   Ljvm/loadingclass/TestClass;
}
SourceFile: "TestClass.java"