为什么 "int i = 2147483647 + 1;" 是可以的,但是 "byte b = 127 + 1;" 却无法编译?

126
为什么 int i = 2147483647 + 1; 是正确的,但是 byte b = 127 + 1; 无法编译?

16
我也有一个真正的疑问:为什么byte数据类型如此麻烦?! - BoltClock
9
“byte” 作为有符号数而不是无符号数,绝对是一个设计错误。 - irreputable
4
当你不知道如何正确使用它时,它才会成为一个痛苦。 - starblue
2
@starblue,Java byte类型在现实生活中有哪些应用实例? - Thorbjørn Ravn Andersen
如果有数据被指定为字节,则出于清晰起见,请使用Java中的byte,例如在参数中。在这种情况下,不能分配int值的事实甚至会捕获一些错误。或者在数组中使用byte来节省空间。我不会仅仅因为一个值恰好适用于一个字节而使用byte - starblue
Josh Bloch总是提到这个问题。在http://www.youtube.com/watch?v=hcY8cYfAEwU的第12分钟左右。 - ahmet alp balkan
4个回答

172

常量被解析成整数,所以2147483647 + 1会导致溢出,并得到一个新的整数。这个新的整数可以赋值给int类型,而127 + 1也被解析为int类型并且等于128,但它不能被赋值给byte类型。


10
实际上,今天我读了一些Java谜题的内容,其中包括一个关于这个问题的谜题......请看这里:http://www.javapuzzlers.com/java-puzzlers-sampler.pdf - 谜题3 - MByD
3
问题在于类型int由于二进制数值提升,数值127只是一个转移注意力的手段。 - starblue
我更喜欢常量在无限精度下进行评估,并且在 int i = 2147483647 + 1; 出现错误。 - Eduardo
@MByD:正如你所说“while 127 + 1 also evaluated as int equals to 128, and it is not assignable to byte.”,这是否意味着50 + 1将被评估为byte,因此可以分配给byte - Bhushan
1
@10101010 - 不完全正确。它可以分配给byte,但是首先(根据标准)它将被评估为int。 - MByD

36

字面量127表示int类型的值,字面量1也是如此。这两个值的总和是整数128。问题在于第二种情况下,你正在将其赋给一个byte类型的变量。这与表达式的实际值无关。这与Java不支持强制转换(*)有关。你必须添加一个类型转换。

byte b = (byte)(127 + 1);

然后它会被编译。

(*) 至少不是像字符串转整数、浮点数转时间这样的类型。如果它们在某种意义上是非丢失的(Java 称之为 "扩展"),则 Java 支持强制转换。

不,单词 "coercion" 不需要纠正。它被有意地和正确地选择了。根据最接近的来源(维基百科):"在大多数语言中,强制转换一词用于表示在编译或运行时期间进行的隐式转换" 和 "在计算机科学中,类型转换、类型转换和强制转换是将一个数据类型的实体隐式或显式地更改为另一个数据类型的不同方式"。


你的代码示例应该是 byte b = (byte)127 + 1;,这是“将1添加到最大化的字节值”的意思,而你的示例只是将 int 值 128 转换为 byte 值。 - NKCSS
6
@NKCSS - 我认为你是错的,这个(byte)(127 + 1)将128(整数)转换为字节,而这个(byte)127 + 1将127转换为字节,但再次转换为int,因为它加上1(int),你得到128(int),错误仍然存在。 - MByD

7
作为对 @MByD 的证明:
以下代码可以编译:
byte c = (byte)(127 + 1);

因为表达式 (127 + 1) 是 int 类型,超出了 byte 类型的范围,所以结果被强制转换为 byte 类型。这个表达式得到的结果是 -128

3

JLS3 #5.2 赋值转换

( variable = expression )

另外,如果表达式是 byte、short、char 或 int 类型的常量表达式(§15.28) :

如果变量的类型是 byte、short 或 char,并且常量表达式的值能够被变量的类型表示,则可以使用缩小原始类型转换。


没有这个条款,我们将无法编写:

byte x = 0;
char c = 0;

但是我们应该这样做吗?我认为不应该。在原始类型之间进行转换时存在很多魔法,必须非常小心。我会尽力编写代码来避免这种情况。

byte x = (byte)0;

关于“我们是否应该能够……”的问题,我认为byte x = 0没有什么问题,但是我是一名C程序员。 - Grady Player
我可能可以理解反对 char c = 0 的观点,但为什么 byte x = 0 是错误的呢? - Michael Burge
对于未经训练的人来说,这是一种误导性的做法,他们会认为将一个字节0分配给一个字节变量。在这个示例中没有太大的危害,但总的来说,操作字节/短整型/字符可能会因为隐式转换而变得非常混乱。它们比人们想象的要复杂得多。我希望我的代码尽可能清晰,不要为了节省几个按键而引入任何不确定性。 - irreputable
@Erwin 不,int i=0L 是非法的。 - irreputable
这是非常好奇的语言设计。 - Erwin Smout
显示剩余3条评论

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