java中的位运算符仅适用于integer和long



我在Eclipse中编写了以下代码:

byte b = 10;
/* some other operations */
b = ~b;

Eclipse希望在逐位补码的行中强制转换为字节。上面写着:"类型不匹配:无法从int转换为byte"。我还在其他位运算和其他积分类型上尝试过这种方法。它与short和char相同。只有long和integer可以使用按位运算。

这是有原因的吗?

Java中的一元(如~)和二元运算符分别对其操作数进行"一元数字提升"(JLS,第5.6.2节)和"二元数字提升(JLS)",这是"首先将事物提升到至少int"的奇特术语。

具体来说,对于一元数字促销,引用上面链接的JLS部分:

某些运算符将一元数字提升应用于单个操作数,该操作数必须生成数字类型的值:

如果操作数是编译时类型的byte、short或char,则通过加宽基元转换将其提升为int类型的值(§5.1.2)。

(二进制数字提升类似,对两个操作数都进行操作。)

因此,即使bbyte~b也是int,因为b的值首先被提升为int

解决方案:将其投射回byte:

b = (byte) (~b);

为什么,Java

这就留下了一个问题,为什么?对于我能找到的操作员来说,在bytes、shorts和chars上操作的JVM字节码指令似乎根本不存在。例如,您使用的一元逐位补码运算符(~)被实现为具有-1(所有位集)的"XOR"运算。来自该链接:

tempSpock &= ~mask;

成为

25 iload_2 // Push local variable 2 (mask).
26 iconst_m1 // Push -1.
27 ixor // Bitwise EXCLUSIVE-OR top two ints: ~mask

然而,我只能为ints和longs找到XOR(以及其他一元和二进制运算符)的指令(在适当的情况下,其他运算符存在floatdouble版本)。

因此,Java必须执行这些提升,因为没有用于在bytes、shorts或chars上执行这些操作的字节码指令。

为什么不呢,JVM

这就引出了另一个问题:为什么JVM不支持这样的字节码指令?答案似乎是,"因为在一个字节的指令集中编码它们太多了。"根据JVM规范,第2.11.1节,

考虑到Java虚拟机的单字节操作码大小,将类型编码为操作码会给其指令集的设计带来压力。如果每个类型化的指令都支持Java虚拟机的所有运行时数据类型,则指令数量将超过一个字节所能表示的数量。相反,Java虚拟机的指令集为某些操作提供了较低级别的类型支持。换句话说,指令集是有意不正交的。根据需要,可以使用单独的指令在不支持和支持的数据类型之间进行转换。

(重点矿井)

总之,JVM的一个字节码指令集排除了bytes、chars和shorts上大多数操作的字节码指令,因此需要一元数字提升和二进制数字提升。

是的,小于int的类型在用作大多数运算符的操作数时会进行提升。它们首先被有效地强制转换为int。因此,在上面的代码中,结果的类型是int。有关详细信息,请参阅JLS的本节。

至于为什么Java会这样做,我不确定。但一个合理的原因是C会这样做,而保持熟悉的语义可能是语言设计的目标。

最新更新