字节码文件揭秘

先以最简单的类结构介绍字节码文件的解析

public class Test {

    private static int a = 12;

    public static void main(String[] args)  {
        System.out.println("dsafad");
    }

}

通过javap -v Test.class命令反编译字节码信息如下:该信息是已经把二进制数据反编译后的结果

public class com.tongweb.uconsole.Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#24         // java/lang/Object."<init>":()V
   #2 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #27            // dsafad
   #4 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Fieldref           #6.#30         // com/tongweb/uconsole/Test.a:I
   #6 = Class              #31            // com/tongweb/uconsole/Test
   #7 = Class              #32            // java/lang/Object
   #8 = Utf8               a
   #9 = Utf8               I
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lcom/tongweb/uconsole/Test;
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               args
  #20 = Utf8               [Ljava/lang/String;
  #21 = Utf8               <clinit>
  #22 = Utf8               SourceFile
  #23 = Utf8               Test.java
  #24 = NameAndType        #10:#11        // "<init>":()V
  #25 = Class              #33            // java/lang/System
  #26 = NameAndType        #34:#35        // out:Ljava/io/PrintStream;
  #27 = Utf8               dsafad
  #28 = Class              #36            // java/io/PrintStream
  #29 = NameAndType        #37:#38        // println:(Ljava/lang/String;)V
  #30 = NameAndType        #8:#9          // a:I
  #31 = Utf8               com/tongweb/uconsole/Test
  #32 = Utf8               java/lang/Object
  #33 = Utf8               java/lang/System
  #34 = Utf8               out
  #35 = Utf8               Ljava/io/PrintStream;
  #36 = Utf8               java/io/PrintStream
  #37 = Utf8               println
  #38 = Utf8               (Ljava/lang/String;)V
{
  public com.tongweb.uconsole.Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/tongweb/uconsole/Test;

  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: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String dsafad
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        12
         2: putstatic     #5                  // Field a:I
         5: return
      LineNumberTable:
        line 5: 0
}
java字节码结构如下:

字节码文件标识说明

 

 

 下面我们将参照java字节码整体结构来解析字节码文件

魔数为固定值在上面可能没有展示

此版本号:0

主版本号:52 【1.8】

类的访问控制权限: ACC_PUBLIC, ACC_SUPER

常量池大小:39 但实际上常量池里面是要减1

常量池:

#1 = Methodref          #7.#24         // java/lang/Object."<init>":()V

表示方法的引用,#7 #24指向常量池中的位置常量

#2 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;

表示字段引用   #25 #26 指向常量池中25,26的位置常量

 #3 = String             #27

String类型,指向常量池中27的位置

 #4 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V

方法引用指向28,29号位置

 #5 = Fieldref           #6.#30         // com/tongweb/uconsole/Test.a:I

字段引用,指向6,30号位置,为整数类型a

#6 = Class              #31            // com/tongweb/uconsole/Test

Class 指向31号位置

#7 = Class              #32            // java/lang/Object

这个应该是父类信息,指向32号位置

#8 = Utf8               a

变量名

#9 = Utf8               I

变量类型

 #10 = Utf8               <init>

初始化方法

 #11 = Utf8               ()V

初始化方法,返回为空

#12 = Utf8               Code

 Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return

         LineNumberTable:
                line 3: 0
              LocalVariableTable:
                Start  Length  Slot  Name   Signature
                    0       5     0  this   Lcom/tongweb/uconsole/Test;

代码

invokespecial指向本实例方法,aload_0表示对this的操作

#13 = Utf8               LineNumberTable

源码行号和字节码行号的对应关系

#14 = Utf8               LocalVariableTable

本地变量表

#15 = Utf8               this

this对象

#16 = Utf8               Lcom/tongweb/uconsole/Test;
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               args
  #20 = Utf8               [Ljava/lang/String;
  #21 = Utf8               <clinit>
  #22 = Utf8               SourceFile
  #23 = Utf8               Test.java

以下是解析main方法和clint静态方法,就不一一说明了,原理是一样的(这个地方我再main中声明了个局部变量,并进行加一操作)

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
     Code:
      stack=2, locals=2, args_size=1
         0: iconst_0
         1: istore_1
         2: iinc          1, 1
         5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         8: ldc           #3                  // String dsafad
        10: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        13: return
      LineNumberTable:
        line 8: 0
        line 9: 2
        line 10: 5
        line 11: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0  args   [Ljava/lang/String;
            2      12     1     b   I

main方法

方法的描述:(参数类型)返回值类型

访问标志:静态,公共

代码:

stack: 最大操作数栈,locals本地变量数量,args_size,形参数量

iconst_0: 将常量压入堆栈

istore_1: 弹出1号位置元素,0号位置是this

iinc 1,1: 增1

getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;

获得常量池中2号位置的静态变量

ldc           #3                  // String dsafad

将常量压入堆栈

invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V

调用实例方法

 static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        12
         2: putstatic     #5                  // Field a:I
         5: return
      LineNumberTable:
        line 5: 0

静态代码块的执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值