我在Eclipse中编写了以下代码:
byte b = 10;
/* some other operations */
b = ~b;
Eclipse希望在按位补码的行中使用强制转换为字节。它说:“类型不匹配:无法从int转换为字节”。我还尝试了其他按位操作和其他整数类型。它与简短和char相同。只有long和整数才能使用按位运算。
这是否有原因?
答案 0 :(得分:12)
Java中的一元(例如~
)和二元运算符分别将其操作数设置为"unary numeric promotion" (JLS, Section 5.6.1)和"binary numeric promotion" (JLS, Section 5.6.2),用于“将事物推广到至少int
的奇特术语”第一”。
具体来说,对于一元数字促销,引用上面链接的JLS部分:
某些运算符将单一数字提升应用于单个操作数,该操作数必须生成数值类型的值:
和
...如果操作数是编译时类型byte,short或char,则通过扩展原语转换(第5.1.2节)将其提升为int类型的值。
(二进制数字促销类似,在两个操作数上运行。)
因此,即使b
是byte
,~b
也是int
,因为b
的值已提升为int
首先。
解决方案:将其投回byte
:
b = (byte) (~b);
为什么,Java?
这就留下了问题,为什么?对于我能找到的运算符来说,在byte
,short
和char
上运行的JVM字节码指令根本不存在。例如,您正在使用的一元按位补码运算符(〜)is implemented as an "XOR" operation with -1
(all bits set)。从那个链接:
tempSpock &= ~mask;
变为
25 iload_2 // Push local variable 2 (mask).
26 iconst_m1 // Push -1.
27 ixor // Bitwise EXCLUSIVE-OR top two ints: ~mask
但是,对于int
和long
s float
和double
版本,我只能find instructions for XOR(以及其他一元和二元运算符)在适当的情况下存在于其他运营商。)
因此,Java必须执行这些促销,因为没有用于在byte
,short
或char
s上执行这些操作的字节码指令。
为什么不,JVM?
这提出了另一个问题:为什么JVM不支持这样的字节码指令?答案似乎是,“因为在一个字节的指令集中对它们进行编码的次数太多了。”根据{{3}},
鉴于Java虚拟机的单字节操作码大小,将编码类型编码到操作码会对其指令集的设计造成压力。如果每个类型化指令都支持所有Java虚拟机的运行时数据类型,那么会有更多指令,而不是字节。相反,Java虚拟机的指令集为某些操作提供了降低级别的类型支持。换句话说,指令集故意不正交。如有必要,可以使用单独的指令在不受支持和支持的数据类型之间进行转换。
(强调我的)
总之,JVM的单字节码指令集排除了byte
,char
和short
上大多数操作的字节码指令,需要一元数字提升和二进制数字推广。
答案 1 :(得分:3)
是的,小于int
的类型在用作大多数运营商的操作数时会进行促销。它们首先被有效地转换为int
。因此,在上面的代码中,结果的类型为int
。有关详细信息,请参阅JLS的this section。
至于为什么 Java这样做,我不确定。但有一个合理的原因是C做到了这一点,维护熟悉的语义可能是语言设计的目标。