繁体   English   中英

Java:为什么我会收到错误消息“类型不匹配:无法将 int 转换为字节”

[英]Java: why do I receive the error message "Type mismatch: cannot convert int to byte"

如果您声明 byte 或 short 类型的变量并尝试对它们执行算术运算,则会收到错误“类型不匹配:无法将 int 转换为 short”(或相应地“类型不匹配:无法将 int 转换为字节”)。

byte a = 23;
byte b = 34;
byte c = a + b;

在这个例子中,编译错误在第三行。

尽管算术运算符被定义为可以对任何数字类型进行运算,但是根据Java语言规范(5.6.2二进制数字提升),字节和short类型的操作数在被传递给运算符之前会自动提升为int。

要对byte或short类型的变量执行算术运算,必须将表达式用括号括起来(在括号内将以int类型进行运算),然后将结果转换回所需的类型。

byte a = 23;
byte b = 34;
byte c = (byte) (a + b);

这是真正的Java专家的一个后续问题:为什么? byte和short类型是完美的数字类型。 为什么Java不允许对这些类型进行直接算术运算? (答案不是“精度下降”,因为没有明显的理由首先将其转换为int。)

更新:jrudolph建议此行为基于JVM中可用的操作,尤其是仅实现全字和双字运算符。 因此,对于字节和短裤运算符,必​​须将它们转换为int。

您的后续问题的答案在这里:

byte和short类型的操作数在交给操作员之前会自动提升为int

因此,在您的示例中,将ab都转换为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)指出,他的例子在正常的有符号算术下也给出了错误的例子。 对于可理解的算法,我们需要任意精度。

在 Java 语言规范(5.6.2 二进制数字提升)中:

1 如果任何表达式为 double 类型,则提升的类型为 double,其他非 double 类型的表达式经历扩展原始转换为 double。

2 否则,如果任何表达式是 float 类型,则提升的类型是 float,并且其他非 float 类型的表达式经历扩展原始转换为 float。

3 否则,如果任何表达式为 long 类型,则提升的类型为 long,并且其他非 long 类型的表达式经历扩展原始转换为 long。

4 否则,所有表达式都不是 double、float 或 long 类型。 在这种情况下,提升的类型是 int,并且任何不是 int 类型的表达式都会经历扩展原始转换为 int。

您的代码属于案例 4。变量ab在交给+运算符之前都转换为int +操作的结果也是int类型而不是byte

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM