Java:为什么我会收到错误消息"类型不匹配:无法将int转换为字节"
如果声明类型为byte或者short的变量并尝试对其进行算术运算,则会收到错误"类型不匹配:无法将int转换为short"(或者相应的"类型不匹配:不能将int转换为byte")。
byte a = 23; byte b = 34; byte c = a + b;
在此示例中,编译错误在第三行。
解决方案
回答
尽管算术运算符被定义为可以对任何数字类型进行运算,但是根据Java语言规范(5.6.2 Binary Numeric Promotion),字节和short类型的操作数在传递给运算符之前会自动提升为int。
要对byte或者short类型的变量执行算术运算,必须将表达式用括号括起来(在其中将以int类型进行运算),然后将结果强制转换为所需的类型。
byte a = 23; byte b = 34; byte c = (byte) (a + b);
这是真正的Java专家的一个后续问题:为什么? byte和short类型是完美的数字类型。为什么Java不允许对这些类型进行直接算术运算? (答案不是"精度下降",因为没有明显的理由首先将其转换为int。)
更新:jrudolph建议此行为基于JVM中可用的操作,尤其是仅实现全字和双字运算符。因此,对于字节和短裤运算符,必须将它们转换为int。
回答
后续问题的答案在这里:
operands of type byte and short are automatically promoted to int before being handed to the operators
因此,在示例中,a
和b
在转换为+运算符之前都被转换为int
。将两个int
加在一起的结果也是一个int
。然后尝试将" int"分配给" byte"值会导致错误,因为可能会导致精度损失。通过显式转换结果,我们将告诉编译器"我知道我在做什么"。
回答
我认为问题是,JVM仅支持两种类型的堆栈值:字大小和双字大小。
然后他们可能决定只需要一个对堆栈上的字长整数进行运算的操作。因此,在字节码级别只有iadd,imul等(并且没有用于字节和短裤的运算符)。
因此,由于这些操作,我们将获得一个int值,而Java无法安全地将其转换回较小的字节和short数据类型。因此,它们迫使我们强制将值缩小为字节/短。
但是最后我们是对的:例如,此行为与int的行为不一致。我们可以毫无疑问地添加两个整数,并且如果结果溢出也不会出错。
回答
Java语言始终将算术运算符的参数提升为int,long,float或者double。因此,采用以下表达式:
a + b
其中a和b是字节类型。这是以下内容的简写:
(int)a + (int)b
此表达式的类型为int。将int值分配给字节变量时,给出错误显然很有意义。
为什么要用这种方式定义语言?假设a为60,b为70,则a + b为-126整数溢出。作为可能导致int的更复杂表达式的一部分,这可能会成为一个困难的错误。限制使用字节和数组存储的简短形式,文件格式/网络协议和拼图的常量。
JavaPolis 2007上有一个有趣的记录。JamesGosling给出了一个例子,说明无符号算术有多么复杂(以及为什么它不在Java中)。乔什·布洛赫(Josh Bloch)指出,他的例子在正常的有符号算法下也给出了错误的例子。对于可理解的算术,我们需要任意精度。