关于java:JVM真香系列轻松理解class文件到虚拟机上

40次阅读

共计 5385 个字符,预计需要花费 14 分钟才能阅读完成。

关注“Java 后端技术全栈”

回复“000”获取大量电子书

意识 JVM

什么是 JVM

JVM 全称 Java Virtual Machine,也就是咱们耳熟能详的 Java 虚拟机。它能辨认 .class 后缀的文件,并且可能解析它的指令,最终调用操作系统上的函数,实现咱们想要的操作。

可能有局部小伙伴学习过 C ++,C++ 开发进去的程序,编译成二进制文件后,就能够间接执行了,操作系统是可能辨认的。

然而咱们开的的 Java 程序就不一样了,应用 javac 命令编译进去的的.class 文件之后,操作系统是不能辨认的,须要对应 JVM 去做一个转换后,操作系统能力辨认。

咱们为什么不能像 C++ 一样,间接在操作系统上运行编译后的二进制文件呢?而非要搞一个处于程序与操作系统中间层的虚拟机呢?

这就是 JVM的过人之处了。大家都晓得,Java 是一门形象水平特地高的语言,提供了主动内存治理等一系列的个性。这些个性间接在操作系统上实现是不太可能的,所以就须要JVM 进行做一系列的转换。

大家一开始学 Java 的时候,就晓得有个 Write Once, Run Everywhere。就是咱们编写了一个 java 文件通过编译成.class 文件后,能够在各种零碎中进行运行。

其实这里是有个前提的,咱们须要在对应操作系统中装置对应的JVM,而后咱们的.class 文件就能运行了。

比方:Windows 操作系统有对应的 JDK 装置版本、Linux 也有对应的 JDK 装置版本等。

意识 JDK

Java Development Kit (JDK) 是 Sun 公司(已被 Oracle 收买)针对 Java 开发员的软件开发工具包。自从 Java 推出以来,JDK曾经成为应用最宽泛的 Java SDK(Software development kit)。

经非官方考察,目前 JDK8 是使用者最多的版本。

JDK14将在 4 月和 7 月收到安全更新,而后由 9 月到期的非 LTS 版本的 JDK 15 取代。JDK14包含 16 项新性能,例如 JDK Flight Recorder 事件流,模式匹配和开关表达式等特色。

JDK9 之后,Oracle 采纳了新的公布周期:每 6 个月公布一个版本,每 3 年公布一个 LTS 版本。JDK14是继 JDK9 之后公布的第四个版本,该版本为非 LTS 版本,最新的 LTS 版本为JDK11

上面是 JDK 版本状况

这个混个眼生就行,随时关注 JDK 版本更新和新个性。

官网地址:https://www.oracle.com/java/

对于 JDK 装置这里就省略。

JDK、JRE、JVM 的关系

下面曾经说过 JDKJVM的相干概念,

JRE全程 Java Runtime Environment,是运行基于 Java 语言编写的程序所不可短少的运行环境。也是通过它,Java 的开发者才得以将本人开发的程序公布到用户手中,让用户应用。

三者到底是什么关系呢?

对于三者关系请看官网

https://docs.oracle.com/javas…

JDK中蕴含 JRE,也包含JDK,而JRE 也包含JDK。范畴关系:JDK>JRE>JVM

“.java” 文件到 ”.class” 文件

javac命令

编写一个 HelloWorld.java 文件

内容就是一个 Java 入门

public class HelloWorld {public static void main(String[] args) {System.out.println("Hello world");
    }
}

关上CMD,进入当前目录,应用命令

javac HelloWorld.java

就编译出HelloWorld.class

编译过程

这个 javac命令过程到底干了些什么呢?

javac背地大抵做了这些操作

这个流程

1、词法剖析

读取源代码,一个字节一个字节的读取,找出其中咱们定义好的关键字(如 Java 中的 if、else、for、while 等关键词,辨认哪些 if 是非法的关键词,哪些不是),这就是词法分析器进行词法剖析的过程,其后果是从源代码中找出规范化的 Token 流。

2、语法分析

通过语法分析器对词法剖析后 Token 流进行语法分析,这一步查看这些关键字组合再一次是否合乎 Java 语言标准(如在 if 前面是不是紧跟着一个布尔判断表达式),词法剖析的后果是造成一个合乎 Java 语言标准的形象语法树。

3、语义剖析

通过语义分析器进行语义剖析。语音剖析次要是将一些难懂的、简单的语法转化成更加简略的语法,后果造成最简略的语法(如将 foreach 转换成 for 循环,好有注解等),最初造成一个注解过后的形象语法树,这个语法树更为靠近目标语言的语法规定。

4、生成字节码

通过字节码生产器生成字节码,依据通过注解的语法形象树生成字节码,也就是将一个数据结构转化为另一个数据结构。最初生成咱们想要的.class 文件。

应用十六进制查看 class 文件内容

我只用的是 Notepad++,选中文本→插件→Converter→ASCII->HEX

class 文件的结尾就是

CAFEBABE

想要学习这里的十六进制的字节码的含意能够参考

https://docs.oracle.com/javas…

javap 查看 class 文件内容

javap是 Java class 文件分解器,能够反编译(即对 javac 编译的文件进行反编译),也能够查看 java 编译器生成的字节码。

新建一个 User.java 源文件,通过 javac 编译后,生成User.classs

package com.tian.demo.test;
public class User {
    private int age = 22;
    private String name = "tian";
    public int addAge() {return age = age + 1;}
    public static void main(String[] args) {}}

应用 javap 命令

javap -v User.class >log.txt

关上log.txt

Classfile /D:/workspace/new/demo/src/main/java/com/tian/demo/test/User.class
  Last modified 2020-11-5; size 441 bytes
  MD5 checksum 2fa72d3f53bd9f138e0bfae82aba67e3
  Compiled from "User.java"
public class com.tian.demo.test.User
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#21         // java/lang/Object."<init>":()V
   #2 = Fieldref           #5.#22         // com/tian/demo/test/User.age:I
   #3 = String             #23            // tian
   #4 = Fieldref           #5.#24         // com/tian/demo/test/User.name:Ljava/lang/String;
   #5 = Class              #25            // com/tian/demo/test/User
   #6 = Class              #26            // java/lang/Object
   #7 = Utf8               age
   #8 = Utf8               I
   #9 = Utf8               name
  #10 = Utf8               Ljava/lang/String;
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               addAge
  #16 = Utf8               ()I
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               SourceFile
  #20 = Utf8               User.java
  #21 = NameAndType        #11:#12        // "<init>":()V
  #22 = NameAndType        #7:#8          // age:I
  #23 = Utf8               tian
  #24 = NameAndType        #9:#10         // name:Ljava/lang/String;
  #25 = Utf8               com/tian/demo/test/User
  #26 = Utf8               java/lang/Object
{public com.tian.demo.test.User();
    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        22
         7: putfield      #2                  // Field age:I
        10: aload_0
        11: ldc           #3                  // String tian
        13: putfield      #4                  // Field name:Ljava/lang/String;
        16: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 10
  public int addAge();
    descriptor: ()I
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: aload_0
         2: getfield      #2                  // Field age:I
         5: iconst_1
         6: iadd
         7: dup_x1
         8: putfield      #2                  // Field age:I
        11: ireturn
      LineNumberTable:
        line 8: 0
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 13: 0
}
SourceFile: "User.java"

魔数与 class 文件版本
常量池
拜访标记
类索引、父类索引、接口索引
字段表汇合
办法表汇合
属性表汇合

而后 JVM 就能够读取这个 User.class 文件进行解析等一系列的操作。

以上就是咱们的 Java 文件到 class 文件。

后续还会更新一系列 JVM 相干文章,敬请期待~

举荐浏览:

《Java Web 企业我的项目实战》.pdf

《MySQL 开发者 SQL 权威指南》.pdf

关注公众号“Java 后端技术全栈”

收费获取 500G 最新学习材料

正文完
 0