Java字节码(二)

一、字节码的执行模型

VM是一台基于栈的计算机器。每个线程都有一个独属于自己的线程栈(JVM stack),

用于存储 栈帧 (Frame)。每一次方法调用,JVM都会自动创建一个栈帧。 栈帧  由操作数栈 , 局部变量数组  以及一个 class引用 组成。 class引用  指向当前方法在运行时常量池中对应的class)。

 

二、方法调用的常见指令

  • invokestatic,顾名思义,这个指令用于调用某个类的静态方法,这是方法调用指令中最

快的一个。

  • invokespecial, 用来调用构造函数,但也可以用于调用同一个类中的 private 方法, 以及

可见的超类方法

  • invokevirtual,如果是具体类型的目标对象,invokevirtual 用于调用公共,受保护和

package 级的私有方法

  • invokeinterface,当通过接口引用来调用方法时,将会编译为 invokeinterface 指令
  • invokedynamic,JDK7 新增加的指令,是实现“动态类型语言”(Dynamically Typed

Language)支持而进行的升级改进,同时也是 JDK8 以后支持 lambda 表达式的实现基

础。

 

三、举个栗子

前面介绍了字节码文件的结果以及常见指令。这里举一个例子,完整的回顾一下上面的知识。

public class ShowJavaByteCode {

    private Integer age;
    public static final int fa = 10;
    public final int fa2 = 30;
    private static int sa = 20;
    static {
        sa = 30;
    }

    public void pirnt(){
        age=10;
        System.out.println("-----------------this is my com.dark.String--------------");
    }

    public static void main(java.lang.String[] args){
        ShowJavaByteCode showJavaByteCode=new ShowJavaByteCode();
        showJavaByteCode.pirnt();
    }
}

这个栗子中包含了以下信息:

  • 属性
  • 静态常量属性
  • 常量属性
  • 静态属性
  • 静态块
  • 一般方法
  • 静态方法

 

字节码内容如下:

Classfile /F:/IdeaProjects/testString/target/classes/com/dark/ShowJavaByteCode.class
  Last modified 2021-3-5; size 1055 bytes
  MD5 checksum ad6dd0d4a42f5da54b4f3ad982b6a775
  Compiled from "ShowJavaByteCode.java"
public class com.dark.ShowJavaByteCode
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #12.#38        // java/lang/Object."<init>":()V
   #2 = Fieldref           #8.#39         // com/dark/ShowJavaByteCode.fa2:I
   #3 = Methodref          #40.#41        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #4 = Fieldref           #8.#42         // com/dark/ShowJavaByteCode.age:Ljava/lang/Integer;
   #5 = Fieldref           #43.#44        // java/lang/System.out:Ljava/io/PrintStream;
   #6 = String             #45            // -----------------this is my com.dark.String--------------
   #7 = Methodref          #46.#47        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #8 = Class              #48            // com/dark/ShowJavaByteCode
   #9 = Methodref          #8.#38         // com/dark/ShowJavaByteCode."<init>":()V
  #10 = Methodref          #8.#49         // com/dark/ShowJavaByteCode.pirnt:()V
  #11 = Fieldref           #8.#50         // com/dark/ShowJavaByteCode.sa:I
  #12 = Class              #51            // java/lang/Object
  #13 = Utf8               age
  #14 = Utf8               Ljava/lang/Integer;
  #15 = Utf8               fa
  #16 = Utf8               I
  #17 = Utf8               ConstantValue
  #18 = Integer            10
  #19 = Utf8               fa2
  #20 = Integer            30
  #21 = Utf8               sa
  #22 = Utf8               <init>
  #23 = Utf8               ()V
  #24 = Utf8               Code
  #25 = Utf8               LineNumberTable
  #26 = Utf8               LocalVariableTable
  #27 = Utf8               this
  #28 = Utf8               Lcom/dark/ShowJavaByteCode;
  #29 = Utf8               pirnt
  #30 = Utf8               main
  #31 = Utf8               ([Ljava/lang/String;)V
  #32 = Utf8               args
  #33 = Utf8               [Ljava/lang/String;
  #34 = Utf8               showJavaByteCode
  #35 = Utf8               <clinit>
  #36 = Utf8               SourceFile
  #37 = Utf8               ShowJavaByteCode.java
  #38 = NameAndType        #22:#23        // "<init>":()V
  #39 = NameAndType        #19:#16        // fa2:I
  #40 = Class              #52            // java/lang/Integer
  #41 = NameAndType        #53:#54        // valueOf:(I)Ljava/lang/Integer;
  #42 = NameAndType        #13:#14        // age:Ljava/lang/Integer;
  #43 = Class              #55            // java/lang/System
  #44 = NameAndType        #56:#57        // out:Ljava/io/PrintStream;
  #45 = Utf8               -----------------this is my com.dark.String--------------
  #46 = Class              #58            // java/io/PrintStream
  #47 = NameAndType        #59:#60        // println:(Ljava/lang/String;)V
  #48 = Utf8               com/dark/ShowJavaByteCode
  #49 = NameAndType        #29:#23        // pirnt:()V
  #50 = NameAndType        #21:#16        // sa:I
  #51 = Utf8               java/lang/Object
  #52 = Utf8               java/lang/Integer
  #53 = Utf8               valueOf
  #54 = Utf8               (I)Ljava/lang/Integer;
  #55 = Utf8               java/lang/System
  #56 = Utf8               out
  #57 = Utf8               Ljava/io/PrintStream;
  #58 = Utf8               java/io/PrintStream
  #59 = Utf8               println
  #60 = Utf8               (Ljava/lang/String;)V
{
  public static final int fa;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: int 10

  public final int fa2;
    descriptor: I
    flags: ACC_PUBLIC, ACC_FINAL
    ConstantValue: int 30

  public com.dark.ShowJavaByteCode();
    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: bipush        30
         7: putfield      #2                  // Field fa2:I
        10: return
      LineNumberTable:
        line 6: 0
        line 10: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Lcom/dark/ShowJavaByteCode;

  public void pirnt();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: bipush        10
         3: invokestatic  #3                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
         6: putfield      #4                  // Field age:Ljava/lang/Integer;
         9: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
        12: ldc           #6                  // String -----------------this is my com.dark.String--------------
        14: invokevirtual #7                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        17: return
      LineNumberTable:
        line 17: 0
        line 18: 9
        line 19: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  this   Lcom/dark/ShowJavaByteCode;

  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: new           #8                  // class com/dark/ShowJavaByteCode
         3: dup
         4: invokespecial #9                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #10                 // Method pirnt:()V
        12: return
      LineNumberTable:
        line 22: 0
        line 23: 8
        line 24: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  args   [Ljava/lang/String;
            8       5     1 showJavaByteCode   Lcom/dark/ShowJavaByteCode;

  static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=0, args_size=0
         0: bipush        20
         2: putstatic     #11                 // Field sa:I
         5: bipush        30
         7: putstatic     #11                 // Field sa:I
        10: return
      LineNumberTable:
        line 11: 0
        line 13: 5
        line 14: 10
}
SourceFile: "ShowJavaByteCode.java"

结合前面介绍的字节码结构来看,加深对字节码的理解。

 

四、总结:

今天介绍了字节码常用指令,并通过一个栗子来把字节码的内容穿起来。加深印象。在字节码中可以证实其中存在默认构造函数,所以默认构造函数是Java编译器生成的, 而不是运行时JVM自动生成的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值