我在Eclipse中编写了以下代码:
byte b = 10; /* some other operations */ b = ~b;
Eclipse希望在按位补码的行中使用强制转换为字节.它说:"类型不匹配:无法从int转换为字节".我还尝试了其他按位操作和其他整数类型.它与简短和char相同.只有long和整数才能使用按位运算.
是否有一个原因?
~
Java中的一元(如)和二元运算符分别使其操作数为"一元数字推广"(JLS,第5.6.1节)和"二进制数字推广"(JLS,第5.6.2节),用于"促进事物"的花哨术语至少int
第一次".
具体来说,对于一元数字促销,引用上面链接的JLS部分:
某些运算符将单一数字提升应用于单个操作数,该操作数必须生成数值类型的值:
和
...如果操作数是编译时类型byte,short或char,则通过扩展原语转换(第5.1.2节)将其提升为int类型的值.
(二进制数字提升类似,在两个操作数上运行.)
所以,即使b
是a byte
,~b
也是一个int
,因为它b
的价值被提升为int
第一个.
解决方案:将其投回到byte
:
b = (byte) (~b);
为什么,Java?
这就留下了问题,为什么?对于我能找到的运算符来说,用于在byte
s,short
s和char
s 上运行的JVM字节码指令根本就不存在.例如,您正在使用的一元按位补码运算符(〜)被实现为"XOR"运算-1
(所有位都设置).从该链接:
tempSpock &= ~mask;
变
25 iload_2 // Push local variable 2 (mask). 26 iconst_m1 // Push -1. 27 ixor // Bitwise EXCLUSIVE-OR top two ints: ~mask
但是,我只能找到XOR指令(和其它一元和二元运算太)为int
S和long
S(float
和double
版本存在在适当情况下其他运营商).
因此,Java必须执行这些促销,因为没有用于在byte
s,short
s或char
s 上执行这些操作的字节码指令.
为什么不,JVM?
这带来了另一个问题:为什么JVM不支持这样的字节码指令?答案似乎是,"因为在一个字节的指令集中对它们进行编码的次数太多了." 根据JVM规范,第2.11.1节,
鉴于Java虚拟机的单字节操作码大小,编码类型到操作码会对其指令集的设计造成压力.如果每个类型化指令都支持所有Java虚拟机的运行时数据类型,那么将会有比在一个字节中表示的指令更多的指令.相反,Java虚拟机的指令集为某些操作提供了降低级别的类型支持.换句话说,指令集故意不正交.可以根据需要使用单独的指令在不支持的数据类型和支持的数据类型之间进行转换.
(强调我的)
总之,JVM的单字节码指令集排除了byte
s,char
s和short
s 上大多数操作的字节码指令,需要一元数字提升和二进制数字提升.