Java虚拟机的字节序问题

37

Java在其虚拟机中使用哪种字节序?我记得曾经在某个地方读到过这取决于它运行的物理机器,而在其他地方,我读到它总是使用大端字节序。哪一个是正确的呢?

2个回答

35

class文件中,多字节数据是以大端方式存储的。

引自Java虚拟机规范,Java SE 7版第4章:class文件格式

类文件由一系列8位字节流组成。所有16位、32位和64位的数据都是通过读取连续的2个、4个或8个8位字节来构造的。多字节数据始终以大端序存储,其中高字节先出现。

此外,如果操作数跨越多个字节,则字节码指令中的操作数也是大端字节序。

引自Java虚拟机规范,Java SE 7版第2.11节:指令集概述

如果操作数的大小超过一个字节,则按照大端序存储,即高阶字节先出现。例如,局部变量中的无符号16位索引被存储为两个无符号字节byte1byte2,其值为(byte1 << 8) | byte2

因此,可以说Java虚拟机使用大端序。


24
这个答案非常误导人。所有的参考资料都解释了多字节值是如何存储在类文件中的。而且类文件确实使用大端序。然而,在运行时,我所知道的所有Java实现都会以本地字节顺序存储变量和数据结构的数据。一旦类文件被加载到更好的可执行格式中,指令操作数很可能也适用于此。如果在诸如i386之类的小端架构上采用其他方式将会非常缓慢。 - Codo
JVM 可以在执行字节码时呈现出大端的外观,同时仍然将多字节值存储在本地字节序中。这里有一个“好像”的规则在起作用,只要 JVM 从其运行的客户代码的视角表现正常,实际的实现细节就是无关紧要的。例如,解释器与 JIT 到本机代码。由于 Java 代码不能轻松地将 int 强制转换为 byte[],因此这个细节通常对在 JVM 中运行的 Java 代码不可见,因此 JVM 可以轻松地使用本地 C 的 int32_t - Peter Cordes
@Codo Java在像i386这样的小端架构上非常慢。如果指令集规定操作需要具有大端参数,则将它们存储为小端会导致更糟糕的性能,因为您必须从小端转换为大端才能使用指令集,然后再次反转为小端进行操作并将结果转换为大端以匹配指令集规范,最后再次转换为小端以将数据存储为大端在生成的文件中。 - Pablo Ariel

21

实际工作数据存储在运行进程中,几乎肯定与执行进程的字节序相匹配。通常文件格式(包括类文件)将采用网络顺序(大端序)。

通常很难知道机器在底层做什么,因为它被虚拟机抽象掉了。你不能像在C和C++中那样将short[]强制转换为byte[]。使用java.nio.ByteOrder.nativeOrder()可以获得底层字节序。当使用非字节NIO缓冲区时,匹配字节序非常有用。


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