关注“Java后端技术全栈”html
回复“000”获取大量电子书java
JVM
全称 Java Virtual Machine,也就是咱们耳熟能详的 Java 虚拟机。它能识别 .class后缀的文件,而且可以解析它的指令,最终调用操做系统上的函数,完成咱们想要的操做。后端
可能有部分小伙伴学习过C++,C++开发出来的程序,编译成二进制文件后,就能够直接执行了,操做系统是可以识别的。安全
可是我们开的的Java程序就不同了,使用javac
命令编译出来的的.class文件以后,操做系统是不能识别的,须要对应JVM
去作一个转换后,操做系统才能识别。数据结构
咱们为何不能像 C++ 同样,直接在操做系统上运行编译后的二进制文件呢?而非要搞一个处于程序与操做系统中间层的虚拟机呢?oracle
这就是 JVM
的过人之处了。你们都知道,Java 是一门抽象程度特别高的语言,提供了自动内存管理等一系列的特性。这些特性直接在操做系统上实现是不太可能的,因此就须要JVM
进行作一系列的转换。jvm
你们一开始学Java的时候,就知道有个Write Once, Run Everywhere。就是咱们编写了一个java文件通过编译成.class文件后,能够在各类系统中进行运行。函数
其实这里是有个前提的,咱们须要在对应操做系统中安装对应的JVM
,而后咱们的.class文件就能运行了。工具
好比:Windows操做系统有对应的JDK
安装版本、Linux也有对应的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
和JVM
的相关概念,
JRE
全程Java Runtime Environment,是运行基于Java语言编写的程序所不可缺乏的运行环境。也是经过它,Java的开发者才得以将本身开发的程序发布到用户手中,让用户使用。
三者究竟是什么关系呢?
关于三者关系请看官网
https://docs.oracle.com/javas...
JDK
中包含JRE
,也包括JDK
,而JRE
也包括JDK
。范围关系:JDK
>JRE
>JVM
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
背后大体作了这些操做
这个流程
读取源代码,一个字节一个字节的读取,找出其中咱们定义好的关键字(如Java
中的if、else、for、while等关键词,识别哪些if是合法的关键词,哪些不是),这就是词法分析器进行词法分析的过程,其结果是从源代码中找出规范化的Token流。
经过语法分析器对词法分析后Token流进行语法分析,这一步检查这些关键字组合再一次是否符合Java
语言规范(如在if后面是否是紧跟着一个布尔判断表达式),词法分析的结果是造成一个符合Java
语言规范的抽象语法树。
经过语义分析器进行语义分析。语音分析主要是将一些难懂的、复杂的语法转化成更加简单的语法,结果造成最简单的语法(如将foreach
转换成for循环 ,好有注解等),最后造成一个注解事后的抽象语法树,这个语法树更为接近目标语言的语法规则。
经过字节码生产器生成字节码,根据通过注解的语法抽象树生成字节码,也就是将一个数据结构转化为另外一个数据结构。最后生成咱们想要的.class文件。
我只用的是Notepad++,选中文本→插件→Converter→ASCII->HEX
class文件的开头就是
CAFEBABE
想要学习这里的十六进制的字节码的含义能够参考
https://docs.oracle.com/javas...
-
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后端技术全栈”
免费获取500G最新学习资料
同步该文章