程序员Java开发那些事程序园

详解 JVM 字节码(2)

2019-05-03  本文已影响12人  zidea
jvm

什么是字节码,为什么需要字节码
编译 JVM 编译成机器码,

我们看一看 Java 编译过程

JVM 接收字节码文件后对其进行校验
验证字节码文件正确性然后通过类加载器加载生成 class 类来运行
【图】

为什么学习字节码?

大家都知道 java 文件编译后为二进制的字节码文件可以被 JVM 读懂,学习好字节码文件可以让我们对 Java 这门语言有深入了解。只要遵循 JVM 规范你就可以创建出自己语言。可以反编译一些第三方库。

java 规范分为两种

这里我们整个字节码分析都会以整个类文件,通过读整个类编译后的字节码来学习字节码。

package com.zidea;

public class Tut {
    private String title = "basic";
    private int courses = 10;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getCourses() {
        return courses;
    }

    public void setCourses(int courses) {
        this.courses = courses;
    }
}

使用 javap 命令查看编译好的 Tut.class 文件

javap Tut.class 
public class com.zidea.Tut {
  public com.zidea.Tut();
  public java.lang.String getTitle();
  public void setTitle(java.lang.String);
  public int getCourses();
  public void setCourses(int);
}

 javap -c Tut.class

用命令查看 class 文件我们可以查看到许多助记符

javap -verbose Tut.class

jangwoodeMacBook-Air:zidea jangwoo$ javap -c Tut.class
Compiled from "Tut.java"
public class com.zidea.Tut {
  public com.zidea.Tut();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #2                  // String basic
       7: putfield      #3                  // Field title:Ljava/lang/String;
      10: aload_0
      11: bipush        10
      13: putfield      #4                  // Field courses:I
      16: return

  public java.lang.String getTitle();
    Code:
       0: aload_0
       1: getfield      #3                  // Field title:Ljava/lang/String;
       4: areturn

  public void setTitle(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #3                  // Field title:Ljava/lang/String;
       5: return

  public int getCourses();
    Code:
       0: aload_0
       1: getfield      #4                  // Field courses:I
       4: ireturn

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

javap -verbose 命令来分析字节码文件
Classfile /Users/jangwoo/IdeaProjects/jvm_demo/out/production/jvm_demo/com/zidea/Tut.class
  Last modified May 2, 2019; size 746 bytes
  MD5 checksum e58553db6eb469ec2411f8711ace986a
  Compiled from "Tut.java"
public class com.zidea.Tut
  minor version: 0
  major version: 54
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #5                          // com/zidea/Tut
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 2, methods: 5, attributes: 1
Constant pool:
   #1 = Methodref          #6.#28         // java/lang/Object."<init>":()V
   #2 = String             #29            // basic
   #3 = Fieldref           #5.#30         // com/zidea/Tut.title:Ljava/lang/String;
   #4 = Fieldref           #5.#31         // com/zidea/Tut.courses:I
   #5 = Class              #32            // com/zidea/Tut
   #6 = Class              #33            // java/lang/Object
   #7 = Utf8               title
   #8 = Utf8               Ljava/lang/String;
   #9 = Utf8               courses
  #10 = Utf8               I
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/zidea/Tut;
  #18 = Utf8               getTitle
  #19 = Utf8               ()Ljava/lang/String;
  #20 = Utf8               setTitle
  #21 = Utf8               (Ljava/lang/String;)V
  #22 = Utf8               getCourses
  #23 = Utf8               ()I
  #24 = Utf8               setCourses
  #25 = Utf8               (I)V
  #26 = Utf8               SourceFile
  #27 = Utf8               Tut.java
  #28 = NameAndType        #11:#12        // "<init>":()V
  #29 = Utf8               basic
  #30 = NameAndType        #7:#8          // title:Ljava/lang/String;
  #31 = NameAndType        #9:#10         // courses:I
  #32 = Utf8               com/zidea/Tut
  #33 = Utf8               java/lang/Object
{
  public com.zidea.Tut();
    descriptor: ()V
    flags: (0x0001) 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: ldc           #2                  // String basic
         7: putfield      #3                  // Field title:Ljava/lang/String;
        10: aload_0
        11: bipush        10
        13: putfield      #4                  // Field courses:I
        16: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      17     0  this   Lcom/zidea/Tut;

  public java.lang.String getTitle();
    descriptor: ()Ljava/lang/String;
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #3                  // Field title:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/zidea/Tut;

  public void setTitle(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #3                  // Field title:Ljava/lang/String;
         5: return
      LineNumberTable:
        line 12: 0
        line 13: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/zidea/Tut;
            0       6     1 title   Ljava/lang/String;

  public int getCourses();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #4                  // Field courses:I
         4: ireturn
      LineNumberTable:
        line 16: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/zidea/Tut;

  public void setCourses(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: iload_1
         2: putfield      #4                  // Field courses:I
         5: return
      LineNumberTable:
        line 20: 0
        line 21: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/zidea/Tut;
            0       6     1 courses   I
}
SourceFile: "Tut.java"

这里我们按顺序了解一下 java 字节码是由哪些部分组成,然后对照创建 Tut的字节码文件进行分析

字节码整体结构
这张表中是按顺序指出我们字节码中内容。

java 字节码中有两种数据类型

魔数

所有 class 字节码文件的前 4 个字节都是魔数,魔数值为固定值CA FE BA BE

屏幕快照 2019-05-02 下午8.36.59.png

单个字节,CA 表示一个字节,C 是 16 进制由 4 位来表示16进制,CA 两个在一起表示 8 位。JVM 编译出来的字节码文件是以 8 位字节为最小单位构成。

上一篇下一篇

猜你喜欢

热点阅读