为什么Java需要对最终变量进行显式强制转换(如果它是从数组中复制的)?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (19)

从下面的代码开始...

byte foo = 1;
byte fooFoo = foo + foo;

当我尝试编译此代码时,我会收到以下错误...

错误:(5,27)java:incompatible types:可能有损于从int到byte的转换

...但如果foo是最终的...

final byte foo = 1;
final byte fooFoo = foo + foo;

该文件将成功编译。

转到下面的代码...

final byte[] fooArray = new byte[1];
fooArray[0] = 1;

final byte foo = fooArray[0];
fooArray[0] = 127;

System.out.println("foo is: " + foo);

...将打印

foo is: 1

......这很好。该值被复制到最终变量,并且不能再被更改。使用数组中的值不会更改foo(如预期的那样)的值。

为什么以下需要演员?

final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
final byte fooFoo = foo + foo;

这与这个问题中的第二个例子有何不同?为什么编译器给我以下错误?

错误:(5,27)java:incompatible types:可能有损于从int到byte的转换

这怎么会发生?

提问于
用户回答回答于

JLS(§5.2)具有用常量表达式进行赋值转换的特殊规则:

此外,如果表达式是一个常量表达式(§15.28类型的)byteshortchar,或int

  • 如果变量的类型是byteshortchar,并且常量表达式的值可以用变量的类型表示,则可以使用缩小的原始转换。

如果我们按照上面的链接,我们可以在常量表达式的定义中看到这些:

  • 原始类型的文字和类型的文字 String
  • 添加剂操作员+-
  • 简称(§6.5.6.1)涉及常量变量(§4.12.4)。

如果我们按照上面的第二个链接,我们可以看到

原始类型或类型的变量String,即final,用一个编译时间常量表达式(初始化§15.28),被称为恒定变量

因此,foo + foo只能分配给fooFooif foo是一个常量变量。将其应用于您的案例:

  • byte foo = 1; 没有定义一个常量变量,因为它不是final
  • final byte foo = 1; 没有定义一个常量变量,因为它是final用一个常量表达式(一个基本文字)初始化的。
  • final byte foo = fooArray[0]; 没有定义常量变量,因为它没有用常量表达式进行初始化。

请注意,是否fooFoo本身final并不重要。

用户回答回答于

很好地适合于一个字节; 1 + 1也是如此; 当变量是final时,编译器可以进行不断的折叠。(换句话说,编译器foo在执行该操作时不使用;但是“raw”1值)

但是,如果变量不是最终的,那么关于转化和促销的所有有趣规则都会引入

对于第二部分:制作数组最终仍然允许您更改其任何字段; 再一次; 不可能持续折叠; 使“widening”的行动再次开始。

扫码关注云+社区