JAVA:字节码和二进制之间有什么区别?

4
Java字节码(编译语言,也称为目标代码)与机器码(本地计算机的代码)有何区别?我在书中读到它们将字节码称为二进制指令,但我不知道原因。

是的,但这些书并没有真正涵盖它。 - TheSilence17
1
“二进制指令”这个名称并不是机器码的一个很好的名称,也不是一个具有明确、特定含义的名称。 - Jesper
在这本书中,他们将字节码称为二进制指令,而不是机器码。 - TheSilence17
1
无论如何,这个说法仍然适用。在这种情况下,“二进制”这个词并没有太多意义。它可能只是用来表示“不可读”。 - Jesper
那么字节码是由一些1和0组成的吗?机器码会是什么样子的呢? - TheSilence17
1
最终,计算机内存中的一切都是由0和1组成的。 - Jesper
2个回答

8

字节码是平台无关的,由Windows上运行的编译器编译的字节码仍然可以在Linux/Unix/Mac中运行。机器码是平台特定的,如果它在Windows x86中编译,则仅能在Windows x86中运行。

继续阅读您的书籍 =)


1
好的,但为什么它被称为二进制而实际上是字节码?难道机器码不应该被称为二进制吗? - TheSilence17
2
字节码和机器码都是二进制的。但是在运行之前,字节码应该被编译成机器码。我建议你阅读这个链接:https://en.wikipedia.org/wiki/Machine_code 以及这个链接:https://en.wikipedia.org/wiki/Bytecode - pohape
3
可以的。Java 代码编译成字节码,字节码再编译成机器码。 - pohape
1
对的,最后一个问题是为什么Java需要将源代码转换为字节码,然后再将其转换为机器码?这样做有什么好处,因为听起来更慢,为什么不直接将其转换为机器码呢? - TheSilence17
4
你可以将源代码编译成平台无关的字节码一次(这个过程很慢),然后每次用户运行你的应用程序时,它将在每个平台上快速地将字节码编译成机器码!每次像源代码一样编译成机器码都太慢了。 - pohape

3

字节码是Java虚拟机的机器语言。当JVM加载一个类文件时,它会为类中的每个方法获取一个字节码流。字节码流储存在JVM的方法区中。当程序运行过程中调用某个方法时,该方法的字节码将被执行。它们可以通过解释,即时编译或者其他技术来执行,这取决于特定JVM的设计者所选择的方法。

每个方法的字节码流都是一系列Java虚拟机指令。每个指令由一个一字节opcode后面跟随着零个或多个操作数组成。opcode表示要执行的动作。如果在JVM可以执行该操作之前需要更多信息,则该信息被编码为一个或多个紧随opcode之后的操作数。

每种类型的opcode都有一个助记符。按照典型的汇编语言风格,Java字节码流可以由其助记符和任何操作数值来表示。例如,下面的字节码流可以通过助记符进行反汇编:

// Bytecode stream: 03 3b 84 00 01 1a 05 68 3b a7 ff f9
// Disassembly:
iconst_0 // 03
istore_0 // 3b
iinc 0, 1 // 84 00 01
iload_0 // 1a
iconst_2 // 05
imul // 68
istore_0 // 3b
goto -7 // a7 ff f9

字节码指令集被设计为紧凑的。除了两个与表跳转有关的指令外,所有指令都在字节边界上对齐。操作码的总数足够小,以至于操作码只占用一个字节。这有助于最小化类文件的大小,在加载到JVM之前可能需要通过网络传输。它还有助于保持JVM实现的大小。
JVM中的所有计算都围绕着堆栈展开。因为JVM没有用于存储任意值的寄存器,所以在计算之前必须将所有内容推送到堆栈上。因此,字节码指令主要在堆栈上运行。例如,在上面的字节码序列中,本地变量首先使用iload_0指令将其推送到堆栈上,然后使用iconst_2将数字2推送到堆栈上,从而将本地变量乘以2。在将两个整数都推送到堆栈上之后,imul指令有效地弹出堆栈上的两个整数,将它们相乘,并将结果再次推送回堆栈上。结果从堆栈顶部弹出,并通过istore_0指令存储回本地变量。JVM被设计为基于堆栈的机器,而不是基于寄存器的机器,以便在像Intel 486这样的寄存器不足的体系结构上实现高效。

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