在 Java 语言白皮书上面有这样一段话:Java 是一种简单的,面向对象的,适用于网络应用的,平台无关的,解释的,健壮的,安全的,结构自然的,可移植的,高性能的,多线程的,动态的语言。
就单从平台无关这一点上面来说,就已经超越 C/C++ 一大截了。就比如说我们在 Windows 下面写出来的一段 Java 程序,换成 Linux,macOS 系统里面,一样可以正常运行并且输出相同的结果,但是这一点,换成 C/C++ 却很难办到。那么跨平台的特性,就是 JVM 决定的了。
JVM 的专业解释如下:
Java 虚拟机(Java Virtual Machine,简称 JVM)是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java 虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。JVM 屏蔽了与具体操作系统平台相关的信息,使 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM 在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。
上面的解释看不懂也比较正常,本来不想把专业解释放上来的,想了想还是算了,毕竟还是要让大家对 JVM 有一点详细的认识。如果看不懂专业解释的话,我就用大白话给大家说:
JVM,也就是 Java 虚拟机,就是一个平台,包含于 JRE 的下面。当你需要执行某个 Java 程序时,由 JVM 帮你进行编译和执行。我们编写的 Java 源码,编译后会生成一种 .class 文件,称为字节码文件。Java 虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。
而且,如图 1 所示,JVM 分为很多个系统版本的,你编写好的 Java 程序,无论到哪个平台上,Windows 也好,Linux 也好,macOS 也好,只需要找到 JVM,便可以成功编译和执行。也就是说,只要在不同平台上安装对应的 JVM,就可以运行字节码文件,运行我们编写的 Java 程序。所以这也就是 Java 跨平台性良好,平台无关特性的来历。
而这个过程中,我们编写的 Java 程序没有做任何改变,仅仅是通过 JVM 这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。
JVM 是一个“桥梁”,是一个“中间件”,是实现跨平台的关键,Java 代码首先被编译成字节码文件,再由 JVM 将字节码文件翻译成机器语言,从而达到运行 Java 程序的目的。
注意:编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过 JVM 翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由 JVM 翻译成的机器码却不一样。
所以,运行 Java 程序必须有 JVM 的支持,因为编译的结果不是机器码,必须要经过 JVM 的再次翻译才能执行。即使你将 Java 程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。
注意:跨平台的是 Java 程序,不是 JVM。JVM 是用 C/C++ 开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的 JVM。
图 1 JVM 实现跨平台
关于JVM的执行效率
Java 推出的前几年,人们有不同的看法,解释字节码肯定比全速运行机器码慢很多,牺牲性能换来跨平台的优势是否值得?
然而,JVM 有一个选项,可以将使用最频繁的字节码翻译成机器码并保存,这一过程被称为即时编译。这种方式确实很有效,致使微软的 .NET 平台也使用了虚拟机。
现在的即时编译器已经相当出色,甚至成了传统编译器的竞争对手,某些情况下甚至超过了传统编译器,原因是 JVM 可以监控运行时信息。例如,即时编译器可以监控使用频率高的代码并进行优化,可以消除函数调用(即“内嵌”)。
但是,Java 毕竟有一些 C/C++ 没有的额外的开销,关键应用程序速度较慢。比如 Java 采用了与平台无关的绘图方式,GUI 程序(客户端程序)执行要慢;虚拟机启动也需要时间。
客户端市场的折戟
Java 的 GUI 库称不上出色,界面不算友好,大部分用户不太习惯;Java 的客户端资源消耗也比较大,大数据量的应用和功能复杂的应用性能堪忧。
更加不能接受的是,微软因自身利益和 SUN 分家后,Windows 便不再预装 JVM 了,用户安装你的程序之前,必须要安装 JVM 并正确设置,你可以要求普通用户安装你的软件,但是你能期望他了解 JVM 的有关知识并正确安装设置吗?
虽然你可以将 JVM 集成在你的程序中,自动安装并设置,不让用户干预,但是你希望附带一个比你的程序还要大好多的 JVM 吗?一个软件这样做或许可以接受,成千上万个软件都这样做,那用户要安装多少个 JVM?磁盘空间要浪费多少?
所以,直接投放市场的面向普通用户的客户端程序,用 Java 开发的很少,大部分 Java 开发的客户端是给企业内部员工使用,员工领到电脑时,技术部已经给配置好了。如果你希望从事客户端开发,建议学习 C/C++ 和 .NET,它们在 Window 客户端开发方面有较大的优势。
种种原因,注定了 Java 客户端不利于推向市场,让普通用户接受。不过话又说回来,客户端开发也不是 Java 的初衷,Java 最初是面向嵌入式的,却随着互联网的兴起而快速成长,在 Web 开发上大显身手。