JVM 字节码_1

浅尝助记符

本章节仅仅是介绍有这些个东西,具体内容详解见后续

package com.ssy.jvm.bytecode;

public class MyTest1 {
    private int a = 1;

    public MyTest1() {
    }

    public int getA() {
        return a;
    }

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

}

    在Terminal中看反编译内容,执行语句javap -c com.ssy.jvm.bytecode.MyTest1

结果

Compiled from "MyTest1.java"
public class com.ssy.jvm.bytecode.MyTest1 {
  public com.ssy.jvm.bytecode.MyTest1();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_1
       6: putfield      #2                  // Field a:I
       9: return

  public int getA();
    Code:
       0: aload_0
       1: getfield      #2                  // Field a:I
       4: ireturn

  public void setA(int);
    Code:
       0: aload_0
       1: iload_1
       2: putfield      #2                  // Field a:I
       5: return
}

    若想看更加详细的一些信息:javap -verbose com.ssy.jvm.bytecode.MyTest1

  • 使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类信息、类的构造方法、类中的方法信息、类变量与成员变量等信息。

  • 魔数:所有的.class字节码文件的前4个字节都是魔数,魔数值为固定值:0xCAFEBABE.(咖啡宝贝哈哈哈哈)

结果

Classfile /Users/ddcc/IdeaProjects/jvm_lecture/out/production/classes/com/ssy/jvm/bytecode/MyTest1.class
  Last modified 2018-10-6; size 491 bytes
  MD5 checksum 4b153cec89fc777dd81db84e9d0b7178
  Compiled from "MyTest1.java"
public class com.ssy.jvm.bytecode.MyTest1
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#21         // com/ssy/jvm/bytecode/MyTest1.a:I
   #3 = Class              #22            // com/ssy/jvm/bytecode/MyTest1
   #4 = Class              #23            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/ssy/jvm/bytecode/MyTest1;
  #14 = Utf8               getA
  #15 = Utf8               ()I
  #16 = Utf8               setA
  #17 = Utf8               (I)V
  #18 = Utf8               SourceFile
  #19 = Utf8               MyTest1.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = NameAndType        #5:#6          // a:I
  #22 = Utf8               com/ssy/jvm/bytecode/MyTest1
  #23 = Utf8               java/lang/Object
{
  public com.ssy.jvm.bytecode.MyTest1();
    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_1
         6: putfield      #2                  // Field a:I
         9: return
      LineNumberTable:
        line 6: 0
        line 4: 4
        line 7: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/ssy/jvm/bytecode/MyTest1;

  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 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/ssy/jvm/bytecode/MyTest1;

  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      #2                  // Field a:I
         5: return
      LineNumberTable:
        line 14: 0
        line 15: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/ssy/jvm/bytecode/MyTest1;
            0       6     1     a   I
}
SourceFile: "MyTest1.java"

真正的二进制文件

Mac推荐使用Hex Fiend工具。
找到MyTest1.class文件打开:
Hex Fiend

我们来针对上面的字节码文件来分析一下含义。

  1. 前4个字节是固定的0xCAFEBABE。
  2. 紧接着的4个字节是版本号信息。前两个是次版本号,后面两个是主版本号。我们对照着javap -verbose

    所以,前两个字节是0,代表次版本号;后两个字节是34(3*16+4=52),也就是主版本号。52对应jdk8等。所以该文件的版本号为1.8.0.可以通过java -version命令来验证这一点。
  3. 常量池(constant pool):紧接着主版本号之后的就是常量池入口。一个Java类定义的很多信息都是由常量池来维护和描述的,可以将常量池看作是class文件的资源仓库,比如说Java类中定义的方法和变量信息,都是存储在常量池中。常量池中主要存储两类常量:字面量与符号引用。字面量如文本字符串,Java中声明为final的常量值等。而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等。
  4. 常量池的总体结构:Java类所对应的常量池主要由常量池数量常量池数组(又叫做常量表)这两部分共同构成。常量池数量紧跟在主版本号后面,占据2个字节;常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都不是不同的,长度当然也就不同;但是每一种元素的第一个数据都是一个u1类型,该字节是个标识位,占据了一个字节。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。值得注意的是,常量池数组中元素个数 = 常量池数量 - 1 (其中0暂时不使用),目的是满足某些常量池索引值的数据在特定情况下需要表达【不引用任何一个常量池】的含义;根本原因在于,索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应null值;所以常量池的索引从1而非0开始。
  5. 在JVM规范中,每个变量/字段都有描述信息,描述信息主要的作用是描述字段的数据类型、方法的参数列表(包括数量、类型与顺序)与返回值。根据描述规则,基本数据类型和代表无返回值的void类型都用一个大写的字符来表示,对象类型则用字符L加对象的全限定名称来表示(包名和类名之间用斜杠)。为了压缩字节码文件的体积,对于基本数据类型,JVM都只用一个大写字母来表示,如下所示:
        B - byte, C - char, D - double, F - float, I - int, J - long, S - short, Z - boolean, V - void, L - 对象类型,如 Ljava/lang/String;
  6. 对于数组类型来说,每一个维度用一个前置的[来表示,如int[]表示为[I; String[][]被表示为[[Ljava/lang/String;
  7. 用描述符来描述方法的时候,按照先参数列表,后返回值的顺序来描述,参数列表按照参数的严格顺序放在一组()之内,如方法String getRealNameByIdAndNickName(int id, String name)的描述符为:(I,Ljava/lang/String;)Ljava/lang/String;

Class文件结构中常量池中11种数据类型的结构总表

现在不止11个,新增了一些getStaticRef什么什么的。。

Class文件结构中常量池中11种数据类型的结构总表
常量项目类型描述
CONSTANT_Utf8_infotagU1值为1
lengthU2UTF-8编码的字符串长度
bytesU1长度为length的UTF-8编码的字符串
CONSTANT_Integer_infotagU1值为3
bytesU4按照高位在前存储的int值
CONSTANT_Float_infotagU1值为4
bytesU4按照高位在前存储的float值
CONSTANT_Long_infotagU1值为5
bytesU8按照高位在前存储的long值
CONSTANT_Double_infotagU1值为6
bytesU8按照高位在前存储的double值
CONSTANT_Class_infotagU1值为7
indexU2指向全限定名常量项的索引
CONSTANT_String_infotagU1值为8
indexU2指向字符串字面量的索引
CONSTANT_Fieldref_infotagU1值为9
indexU2指向声明字段的类或者接口描述符Constant_Class_info的索引项
indexU2指向字段描述符CONSTANT_NameAndType_info索引项
CONSTANT_Methodref_infotagU1值为10
indexU2指向声明方法的类描述符CONSTANT_Class_info的索引项
indexU2指向名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_InterfaceMethodref_infotagU1值为11
indexU2指向声明方法的接口描述符CONSTANT_Class_info的索引项
indexU2指向名称及类型描述符CONSTANT_NameAndType_info的索引项
CONSTANT_NameAndType_infotagU1值为12
indexU2指向字段或方法名称常量项的索引
indexU2指向字段或方法描述符常量项的索引
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值