当Java需要JVM来运行时,它如何实现跨平台?

81

我刚开始学习Java,对于平台无关性这个主题感到困惑。

“无关性”难道不意味着Java代码应该可以在任何计算机上运行,并且不需要安装特殊软件吗?然而,JVM需要在计算机上安装。

例如,我们需要Turbo C编译器才能编译C / C ++源代码,然后执行它。计算机必须安装C编译器。

请问当Java被描述为“平台无关”的时候,这是什么意思?


4
据我最后查看的情况,它可以在 Borland 的网站上免费下载。 - dan04
1
是的,被列为古董软件...(http://edn.embarcadero.com/article/20841)。 - Matthew Flaschen
2
执行编译后的程序不需要Turbo C(或任何其他“本地”编译器)。编译器会生成一个.exe文件。最多只需要运行时库(在一个.dll文件中),而不是整个编译器。 - Javier
24个回答

115

通常,编译后的代码是CPU执行程序所需的精确指令集。在Java中,编译后的代码是一组针对“虚拟CPU”的精确指令集,该CPU必须在每台物理机器上都能正常工作。

因此,在某种程度上,Java语言的设计者决定使语言和编译后的代码无平台依赖性,但由于代码最终必须在物理平台上运行,他们选择将所有平台相关的代码放在JVM中。

这种需要JVM的要求与您使用的Turbo C示例相反。对于Turbo C,编译器将生成平台相关的代码,而且不需要类似于JVM的工具,因为CPU可以直接执行已编译的Turbo C程序。

对于Java而言,CPU执行JVM,而JVM又是平台相关的。运行JVM会执行Java字节码,而这些字节码是平台无关的,前提是有可用的JVM来执行它。你可能会说,编写Java代码时,你不是在编写要在物理机器上执行的代码,而是在编写要在Java虚拟机上执行的代码。

所有这些Java字节码在所有Java虚拟机上运行的唯一方式是编写了一个非常严格的标准来规定Java虚拟机的工作方式。这意味着,无论你使用哪个物理平台,Java字节码与JVM接口的部分都保证只能以一种方式工作。由于所有JVM都完全相同,因此相同的代码在任何地方都可以完全相同而无需重新编译。如果不能通过测试以确保其相同,则不允许将虚拟机称为“Java虚拟机”。

当然,有些方法会破坏Java程序的可移植性。例如,您可能编写仅在一个操作系统上才有的文件的程序(例如cmd.exe)。您可以使用JNI,它实际上允许将已编译的C或C ++代码放入类中。您可能会使用仅适用于某个操作系统的约定(例如假定“:”分隔目录)。但是,除非您在进行一些特殊操作(如JNI),否则保证您永远不必为不同的计算机重新编译程序。


1
由于所有的JVM都完全相同,同样的代码在任何地方都可以不重新编译而正常运行。这句话的意思是,只要安装了JVM,无论在哪个系统上运行相同的程序,我们都不需要再次进行“javac filename.java”这样的编译操作(以任何简单程序为例)。如果不需要重新编译程序,那么为什么说“我们可以在任何地方运行相同的代码而不需要重新编译”呢?请解释一下。 - Karan Thakkar
3
你需要编译Java源代码,因此需要使用“javac filename.java”命令。然而,你只需要编译一次,不需要在每台计算机上都编译(这与C和C ++不同)。如果更改CPU、32/64位系统、字节顺序等,代码仍然可以运行。这是因为输出的“filename.class”包含了字节码,这些字节码是给JVM的指令。由于所有JVM都是功能相同的,一旦编译了代码,就可以在任何Java虚拟机上运行该字节码而不需要源代码。试试吧,它可以工作。同时,你所提到的一些评论混淆了编译和重新编译的概念。 - Edwin Buck
@KaranThakkar - 我认为Edwin想要表达的意思的扩展可能是,在任何平台上,都可以轻松地使用相同的.jar文件在您的项目中,而无需编译它们。 - vanguard69

54
            Technical Article on How java is platform indepedent?

在深入讲解之前,首先你需要明白什么是平台的意思?平台由计算机硬件(主要是微处理器架构)和操作系统组成。平台=硬件+操作系统。

任何平台无关的内容都可以在任何操作系统和硬件上运行。

Java是平台无关的,因此Java可以在任何操作系统和硬件上运行。现在的问题是它是如何做到平台无关的呢?

这是因为字节码的神奇之处,它是操作系统无关的。当Java编译器编译任何代码时,它生成的是字节码而不是机器本机代码(不像C编译器)。现在这个字节码需要一个解释器来在一台机器上执行,这个解释器就是JVM。所以JVM读取那个机器无关的字节码并执行它。不同的JVM被设计用于不同的操作系统,并且字节码可以在不同的操作系统上运行。

对于C或C++(不是平台无关的语言),编译器生成的是依赖于操作系统的.exe文件,因此当我们在另一个操作系统上运行此.exe文件时,它将无法运行,因为该文件是依赖于操作系统的,所以与另一个操作系统不兼容。

最后,一个中间的操作系统无关字节码使得Java具有平台无关性。


5
这是一个愚蠢的回答。使Java平台独立的原因是Java依赖于虚拟机(VM)。只要该VM满足对操作系统操作的调用,Java就不关心它运行在什么操作系统上。但VM本身并不是平台无关的。你提供的与C/C++语言的比较是错误的,只需在相应的平台上编译源代码就可以运行了,为什么要将这组指令带到不同的平台上,并愚蠢地期望它能运行呢?你能将你的Java源代码带到ARM上,并期望它在为我的自定义处理器编译的VM上运行吗? - Abhinav Gauniyal
JVM的设计是相同的。Oracle不会为每台机器设计不同的JVM而感到疯狂。唯一的区别是您想在某台机器上运行的程序的字节码。每个程序生成不同类型的字节码。字节码文件采用十六进制格式,以便JVM和CPU理解并执行指令集。 - Karan Thakkar

25

这意味着Java程序员理论上不需要知道机器或操作系统的详细信息。尽管这些细节确实存在,但JVM和类库会处理它们。此外,与C形成鲜明对比的是,Java二进制代码(字节码)通常可以移植到完全不同的系统而无需修改或重新编译。


10
Java二进制文件(字节码)通常可以在完全不需要重新编译的情况下移植到完全不同的架构。实际上,它们总是可以这样做。只有在将为较新的JVM编译的代码移动到较旧的JVM时才需要重新编译。 - Stephen C
@Stephen,我把它改成了“系统”。有许多因素可能会阻碍可移植性,包括使用JNA或JNI链接到仅针对单个架构编写的库。 - Matthew Flaschen
1
对我来说,JNA或JNI似乎是唯一的因素,但在现实世界中它们非常罕见。即使如此,字节码仍然可以在不重新编译的情况下移动 - 只是您可能还需要重新编译JNI期望存在的库。但是,字节码仍然是可移植的。 - Kendall Helmstetter Gelner
同意...但在这些情况下,重新编译“Java二进制代码(字节码)”都不会有任何区别! - Stephen C
我有一个问题,编译后的Java字节码是否与操作系统内核进行交互?如果是这样的话,由于内核函数不同,相同的字节码不能应用于不同的内核,对吗?还是JVM包含了每个不同内核的所有内核函数,这是非常难以置信的... - henryyao
@henryyao,不,字节码并不是为真实的机器编写的,也不能直接与内核通信。在简单(非现代)的JVM实现中,JVM只是一步一步地解释执行。在现代的实现中,它被重新编译成机器码,并且那个后者的机器码直接在CPU上运行(可能使用内核中断,不确定)。 - Matthew Flaschen

8

JVM是一种可以安装在不同系统上的“模拟机器”。这样,相同的Java代码可以在不同的系统上运行,因为它依赖于JVM,而不是操作系统本身。

也就是说,这使得程序员可以与虚拟系统(JVM)通信并利用其功能,而不是特定机器和操作系统的功能。由于Java只依赖于JVM,所以它是平台无关的(如果平台安装了JVM)。

因此,简而言之,Java本身并非平台无关的,它需要在应该运行的所有系统上安装JVM。然而,只要系统安装了JVM,Java就可以在所有这些系统上运行。


8
不,情况恰恰相反。正是因为您使用虚拟机,Java程序才变得独立。
虚拟机并不是独立的,您需要安装一个特别针对您的系统类型的虚拟机。虚拟机在操作系统之上创建了一个独立的平台。

5

Java是平台无关的,因为它有JVM(Java虚拟机)。我们用一个真实的例子来解释一下。假设你可以自由地与你的家人交流。但是为什么呢?因为你很了解他们,他们也很了解你。但是,你不能自由地和我的家人交流。因为你不认识他们,他们也不认识你。但是,如果我是你的朋友,并且我能介绍你给我的家人认识,那么你就能够自由地和他们交流。

类似地,如果你是代码,而我是JVM。你的家人使用的是Windows平台,而我的家人使用的是Linux平台。如果你使用的是C或其他平台相关语言,你只能认识你的家人成员,反之亦然。这就是为什么只有编写该代码的平台才知道该代码并支持它。但是,如果你使用的是Java代码,当你进入我的家庭即Linux平台时,如果你找到我,JVM,我就可以介绍你给我的家人——Linux平台,让你能够与其交互。

对于平台相关的语言,没有像JVM这样的“朋友”可以向他们介绍自己的家族。这就是Java平台无关的原因。 :)


3

JVM从具体平台中抽象出来。您的程序仅依赖于JVM,由于JVM可用于不同的平台,如Windows和Linux,因此您的程序是独立于平台的(但依赖于JVM)。


3

Java不是跨平台的,它本身就是一个平台,基于这个平台运行Java应用程序,但是Java平台本身是平台相关的。


3
在c / c ++中,经过编译器编译的源代码(c程序文件)直接转换为本机机器代码(该代码适用于编译该代码的特定机器),因此c / c ++的编译代码无法在不同的操作系统上运行。
但是,在Java中:使用JAVAC编译器(JDK中存在)编译java的源文件(.java),提供可在任何安装在任何OS上的JVM上理解的字节码(.class文件)。
在这里,我们需要为我们想要运行代码的不同操作系统拥有不同的JVM(其依赖于平台),但是.class文件(已编译的代码/中间代码)保持相同,因为它可以理解在任何OS上安装的任何JVM。
在c / c ++中:只有源代码是机器无关的。 在Java中:源代码和编译代码都是跨平台的。
这使得Java平台(机器)独立。

2

JVM是与操作系统相关的。 对于每个操作系统,JVM都是不同的。

“.class”对于所有JVM都是相同的。 因此,每个JVM都可以理解“.class”文件数据。

Windows依赖的JVM会向Windows提供Windows依赖的指令, Linux依赖的JVM会向Linux提供Linux依赖的指令。

其他操作系统也是如此。 因此,Java可以在任何操作系统上运行。

这就是为什么Java是操作系统无关的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接