Java中的原始转换和分配

我明白为什么以下是错误的:

byte a = 3; byte b = 8; byte c = a + b; // compile error 

它不会编译。 expression式总是导致int 。 所以我们应该做一下明确的演员:

 byte c = (byte) (a + b); // valid code 

我不明白为什么以下是正确的

 byte d = 3 + 8; // it's valid! why? 

因为文字整数(如3或8)总是隐含的int 。 而int-or-smallerexpression式总是会导致int 。 有人可以解释这里发生了什么吗?

我唯一能猜到的是编译器将这个expression式等同于下面的内容:

 byte d = 11; 

并不认为这是一个expression。

在编译时, 3 + 8是否被评估为11 ,这与编译器明确允许在某些情况下隐含地将int缩小到byte s有关。 特别是,语言规范明确允许隐式缩小转换为types为int的常量expression式的byte ,它可以在编译时适合一个byte

JLS的相关部分是§5.2:

另外,如果expression式是byteshortcharinttypes的常量expression式(第15.28节):

  • 如果variables的types是byteshortchar并且常量expression式的值可以用variables的types表示,则可以使用缩小的原始转换。

编译时缩小的常量意味着代码如: byte theAnswer = 42; 被允许。 如果没有缩小,那么整数文字42types为int的事实将意味着需要强制转换为byte

†:显然,按照规范,常量expression式需要进行评估,看它是否适合更窄的types。 但是要指出的是,如果没有这部分规范,编译器将不被允许进行隐式缩小转换

让我们在这里明确:

 byte a = 3; byte b = 8; 

这些被允许的原因是由于上面的规范部分。 也就是说,允许编译器将文字3的隐式缩小转换为一个byte 。 这不是因为编译器在编译时将常量expression式3为值3

我唯一能猜到的是编译器将这个expression式等同于下面的内容:

是的,它确实。 只要右边的expression式是由常量组成的 (这符合所需的基本types – 请参阅@Jason对JLS所说的完全相同的答案),您可以这样做。 这将不会编译,因为128超出范围:

 byte a = 128; 

请注意,如果你像这样转换你的第一个代码片段:

 final byte a = 3; final byte b = 8; byte c = a + b; 

它编译! 由于你的两个字节是final 它们的expression式是常量,所以这次编译器可以确定当第一次初始化时,结果将适合一个字节。

但是,这不会编译:

 final byte a = 127; // Byte.MAX_VALUE final byte b = 1; byte c = a + b // Nope... 

编译器会错误地输出一个“可能的精度损失”。

这是因为38编译时间常量。

因此,在编译时,编译器可以确定3 + 8可以放入一个bytevariables中。

如果你把你的ab变成final(常量)variables。 a + b将成为编译时间常量。 所以编译没有任何问题。

  final byte a = 3; final byte b = 8; byte c = a + b;