编译语言与解释语言
编译语言就是类似于C语言这种,在运行真正的代码之前先需要进行编译的语言,编译之后将会直接变为当前系统可直接读取的文件类型,例如你在windows上编译C语言之后得到的o文件,他其实就是机器码文件,直接运行这个文件就能直接控制硬件。好处是编译完毕之后非常的快,缺点是移植性弱。
解释语言就是类似于Python,JS这种,他们是一行一行的读取代码然后进行翻译,执行一行翻译一行,所以运行的比较慢。好处是移植性强,不依赖平台。缺点就是运行的慢。
而Java是编译+解释语言。Java代码经过编译之后变为class文件,也就是字节码文件。而字节码文件经过JVM解释器之后可以解释为对应的机器码。
什么是字节码?
字节码:Java源代码经过虚拟机编译器(注意这个编译器是虚拟机提供的)编译后产生的文件(即扩展为.class的文 件),它不面向任何特定的处理器,只面向虚拟机。
采用字节码的好处:
Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效, 而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。
Java的编译器和解释器
Java中引入了虚拟机(JVM)的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。
在Java中,这种供虚拟机理解的代码叫做字节 码(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器(例如Windows和Linux平台他们对文件的操作方式就是不一样的)是不同的,但是实现的虚拟机是相同的(也就是一样的字节码文件,操作的还是某一种对应的功能,例如你使用的File,他们都是操作某一个文件)。
Java源程序经过编译 器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行,这就是上面提到的Java的特点的编译与解释并存的解释
补充一点,就是我们根据我们的环境(Windows或者LInux的JDK)安装完毕JDK之后(其中包含了JVM),然后我们使用JDK编写完毕代码并且进行编译时,我们在IDE中编写的每一行Java代码都会被这个JDK提供的编译程序编译为当前JVM可以理解的字节码。而这些字节码被JVM解释器解释之后会变为机器可以执行的二进制机器码。所以这就是某些程序的运行要求你使用特定的JDK版本,因为不同版本的JDK他们的JVM实现可能不一样,所以很多的程序下载完毕之后他们都会在他们的包中自带一个能够使该项目运行的JDK。
Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中 解释器-----> 机器可执行的二进制机器码---->程序运行。
Java 程序从源代码到运行一般有下面 3 步:
我们需要格外注意的是 .class->机器码 这一步。在这一步 jvm 类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的,也就是所谓的热点代码,所以后面引进了 JIT 编译器,JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言。
HotSpot 采用了惰性评估(Lazy Evaluation)的做法,根据二八定律,消耗大部分系统资源的只有那一小
部分的代码(热点代码),而这也就是 JIT 所需要编译的部分。JVM 会根据代码每次被执行的情况收集信息并相应地做出一些优化,因此执行的次数越多,它的速度就越快。JDK 9 引入了一种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了 JIT 预热等各方面的开销。JDK 支持分层编译和 AOT 协作使用。但是 ,AOT 编译器的编译质量是肯定比不上 JIT 编译器的。
总结:Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。