详解 JVM 字节码(2)

jvm

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

我们看一看 Java 编译过程

  • java 源码
  • 编译为 class 文件

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

为什么学习字节码?

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

java 规范分为两种

  • java 语言本身的规范
  • JVM 的规范。字节码属于 JVM 规范。JVM 只是关心字节码

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

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 命令来分析字节码文件

  • 魔数
  • 版本号
  • 常量池
  • 类信息 ,class 信息不会丢失在进入 JVM
  • 类的构造方法
  • 类中的方法信息
  • 类变量与成员变量等信息
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 字节码中有两种数据类型

  • 字节数据直接量:为基本的数据类型,例如 u1、u2、u4 和 u8,分别代表连续的 1 字节、2 字节、4字节和 8 字节组成整体数据。
  • 表(数组):表是由多个基本数据或其他表,按照既定顺序组成的数据集合。例如常量池就是表。
    其中表长度是不固定的,他是元素类型(不同类型有不同内容)和元素数量决定。

魔数

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

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

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

如果有想学习java的程序员,可来我们的java学习扣qun:697699179,免费送java的视频教程噢!我每晚上8点还会在群内直播讲解Java知识,欢迎大家前来学习哦。

猜你喜欢

转载自blog.csdn.net/sdssdfh/article/details/89790776