Java中的位运算符只适用于整数和长整数吗?

5

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

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

Eclipse在按位取反的行中需要将类型转换为byte。它报错说:“类型不匹配:无法从int转换为byte”。我还尝试了其他按位运算和其他整数类型,但对于short和char也是一样的。只有long和integer可以使用按位运算。

这是为什么呢?


1
也许是因为计算机需要在至少32位长的寄存器上执行操作? - user2573153
是的!那可能就是原因。 - Michael Langhammer
2个回答

13

Java中的一元(例如~)和二元运算符分别对其操作数进行"一元数值提升"(JLS,第5.6.1节)"二元数值提升"(JLS,第5.6.2节),这些术语指的是“首先将事物提升至至少int类型”。

具体而言,在一元数值提升中,引用上述链接的JLS部分:

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

......如果操作数的编译时类型为byte、short或char,则通过扩展原始转换(§5.1.2)将其升级为int类型的值。

(二元数值提升类似,作用于两个操作数。)

所以,即使b是一个byte~b也是一个int,因为b的值首先被升级为int。解决方案:将其强制转换回byte
b = (byte) (~b);

为什么选择Java?

那么问题来了,为什么选择Java呢?似乎对于我能找到的运算符,操作byteshortchar类型的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

然而,我只能找到针对intlongXOR指令的说明(以及其他一元和二元运算符),(其他运算符的floatdouble版本也存在)。
因此,Java必须执行这些提升操作,因为没有字节码指令可用于在byteshortchar上执行这些操作。 JVM为什么不支持这样的字节码指令呢? 这带来了另一个问题:为什么JVM不支持这样的字节码指令?答案似乎是“因为在一个字节的指令集中编码所有这些指令将会太多”。根据JVM规范第2.11.1节的说法,
鉴于Java虚拟机的一字节操作码大小,将类型编码到操作码中会对其指令集的设计施加压力。如果每个类型化指令都支持Java虚拟机的所有运行时数据类型,则指令数量将超过一个字节所能表示的范围。相反,Java虚拟机的指令集为某些操作提供了较低级别的类型支持。换句话说,指令集故意不是正交的。必要时可以使用单独的指令在不支持和支持的数据类型之间进行转换。
(强调我的)
总之,JVM的一字节代码指令集排除了大多数操作的字节、字符和短整型字节码指令,需要进行一元数字提升和二元数字提升。

你所传递的字节码参数毫无意义。如果该语言规定了,编译器可以很好地添加强制类型转换。例如,可以看看如何在“short”上定义“+=”。 - starblue

4
是的,比 int 小的类型在大多数操作符中使用时会经历 提升。它们被有效地转换为 int。因此,在你上面的代码中,结果的类型是 int。详见 JLS 的这个章节

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


请问您能提供在C语言中定义此行为的参考资料吗? - Marc Kees

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