Java虚拟机(JVM) - 字节码

一、什么是字节码?

1、字节码概述

        Java 字节码是 Java 虚拟机的指令集。它的作用类似于汇编器,汇编器是 C++ 代码的别名表示。一旦编译了 java 程序,就会生成 java 字节码。用更恰当的术语来说,java 字节码是 .class 文件形式的机器码。在 java 字节码的帮助下,我们在 java 中实现了平台独立性。

2、字节码与汇编语言

        字节码类似于汇编语言,因为它不是高级语言,但与机器语言不同,它仍然具有一定的可读性。两者都可以被认为是介于源代码和机器代码之间的“中间语言”。两者的主要区别在于,字节码是为虚拟机(软件)生成的,而汇编语言是为CPU(硬件)生成的。

二、它是如何工作的?

        当我们用 Java 编写程序时,首先,编译器编译该程序并为该代码生成一个字节码。当我们希望在任何其他平台上运行这个 .class 文件时,我们可以这样做。在第一次编译之后,生成的字节码现在由 Java 虚拟机运行,而不是考虑的处理器。这实质上意味着我们只需要在我们想要运行代码的任何平台上安装基本的 java 即可。运行字节码所需的资源由 Java 虚拟机提供,它调用处理器来分配所需的资源。JVM 是基于堆栈的,因此它们堆栈实现以读取代码。

三、Java字节码的优势

        平台独立性是James Gosling赋予java的重要特性之一,正是这种字节码的实现帮助我们实现了这一点。因此,字节码是任何 java 程序的一个非常重要的组成部分。JVM 的指令集可能因系统而异,但都可以解释字节码。要记住的一点是,字节码是不可运行的代码,并且依赖于解释器的可用性来执行,因此 JVM 开始发挥作用。

        字节码本质上是在 Java 虚拟机上运行的机器级语言。每当加载一个类时,它都会为该类的每个方法获取一个字节码流。每当在程序执行期间调用该方法时,都会调用该方法的字节码。Javac 不仅编译程序,还为程序生成字节码。因此,我们已经意识到字节码的实现使 Java 成为一种平台无关的语言。这有助于为 Java 添加 C 或 C++ 等语言所缺乏的可移植性。可移植性确保 Java 可以在桌面、移动设备、服务器等各种平台上实现。为了支持这一点,Sun Microsystems 将 JAVA 命名为“一次编写,随处读取”或“WORA”与字节码解释产生共鸣。

四、如何查看字节码

        通过javac和javap查看:先通过javac将.java文件编译成.class字节码文件,然后通过javap -verbose分析字节码。

1、javap命令说明

  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

2、输出附加信息

javap -verbose Base

        输出如下

Classfile /C:/Program Files/Java/jdk1.8.0_91/bin/Base.class
  Last modified 2022-3-6; size 218 bytes
  MD5 checksum 9a79a6c59f787265dae97730351d7e23
  Compiled from "Base.java"
abstract class Base
  minor version: 0
  major version: 52
  flags: ACC_SUPER, ACC_ABSTRACT
Constant pool:
   #1 = Methodref          #3.#12         // java/lang/Object."<init>":()V
   #2 = Class              #13            // Base
   #3 = Class              #14            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               method1
   #9 = Utf8               method2
  #10 = Utf8               SourceFile
  #11 = Utf8               Base.java
  #12 = NameAndType        #4:#5          // "<init>":()V
  #13 = Utf8               Base
  #14 = Utf8               java/lang/Object
{
  Base();
    descriptor: ()V
    flags:
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public abstract void method1();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_ABSTRACT

  public abstract void method2();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "Base.java"

3、 对代码进行反编译

javap -c Base.class

        输出如下

​Compiled from "Base.java"
abstract class Base {
  Base();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public abstract void method1();

  public abstract void method2();
}

4、Idea配置宏

Idea2017查看Class字节码文件_kingolie的博客-CSDN博客_idea查看class源码Idea查看字节码文件的原理1、javap命令的使用在jdk工具包的bin目录下,有一个java可执行文件javap,该工具可以查看java编译后的class文件。使用命令如下命令进行查看:javap -c Student 此处Student为Student.class文件 -c: 选项可以查看对代码的反汇编代码2、Idea2017下配置宏首先进入Idea,打开File->Settings。选择https://blog.csdn.net/kingolie/article/details/79324138

五、虚拟机字节码指令集

        下图是部分示例。详见Java 虚拟机指令集

Chapter 6. The Java Virtual Machine Instruction Sethttps://docs.oracle.com/javase/specs/jvms/se12/html/jvms-6.html#jvms-6.5.nop

六、简单示例

1、类代码

package com.algorithm.demo.algorithms;

public class ByteCodeTest{

    public static void InitAndAdd()
    {
        int i=99;
        i++;
    }

}

2、字节码

Compiled from "ByteCodeTest.java"
public class com.algorithm.demo.algorithms.ByteCodeTest {
  public com.algorithm.demo.algorithms.ByteCodeTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void InitAndAdd();
    Code:
       0: bipush        99
       2: istore_0
       3: iinc          0, 1
       6: return
}

        让我们关注InitAndAdd方法。

        1、int i=99; 对应下面两步操作

0: bipush        99        //将一个 byte 压入操作数栈(其长度会补齐 4 个字节)

2: istore_0                //将 int 存储到局部变量中

        2、i++; 对应下面两步操作

       3: iinc          0, 1        //递增局部变量
       6: return                        //返回

猜你喜欢

转载自blog.csdn.net/bashendixie5/article/details/123221228